SQL Server'da sayısal aralık (aralık) aramalarını en iyileştirme


18

Bu soru IP Aralığı Arama Optimizasyonu'na benzer mi? ancak bu SQL Server 2000 ile sınırlıdır.

Aşağıdaki şekilde yapılandırılmış ve doldurulmuş bir tabloda geçici olarak depolanmış 10 milyon aralığım olduğunu varsayalım.

CREATE TABLE MyTable
(
Id        INT IDENTITY PRIMARY KEY,
RangeFrom INT NOT NULL,
RangeTo   INT NOT NULL,
CHECK (RangeTo > RangeFrom),
INDEX IX1 (RangeFrom,RangeTo),
INDEX IX2 (RangeTo,RangeFrom)
);

WITH RandomNumbers
     AS (SELECT TOP 10000000 ABS(CRYPT_GEN_RANDOM(4)%100000000) AS Num
         FROM   sys.all_objects o1,
                sys.all_objects o2,
                sys.all_objects o3,
                sys.all_objects o4)
INSERT INTO MyTable
            (RangeFrom,
             RangeTo)
SELECT Num,
       Num + 1 + CRYPT_GEN_RANDOM(1)
FROM   RandomNumbers 

Değeri içeren tüm aralıkları bilmek gerekir 50,000,000. Aşağıdaki sorguyu deniyorum

SELECT *
FROM MyTable
WHERE 50000000 BETWEEN RangeFrom AND RangeTo

SQL Server, 10.951 mantıksal okuma olduğunu ve eşleşen 12 kelimeyi döndürmek için yaklaşık 5 milyon satır okunduğunu gösterir.

resim açıklamasını buraya girin

Bu performansı artırabilir miyim? Tablonun veya ek dizinlerin yeniden yapılandırılması iyidir.


Tablonun kurulumunu doğru bir şekilde anlıyorsam, aralıklarınızı oluşturmak için her bir aralığın "boyutu" üzerinde herhangi bir kısıtlama olmadan rastgele sayılar seçersiniz. Probunuz, toplam 1,00M aralığının ortası içindir. Bu durumda - üniform rasgelelik nedeniyle belirgin bir kümelenme yok - Alt veya üst sınırdaki bir endeksin neden yararlı olacağını bilmiyorum. Bunu açıklayabilir misin?
davidbak

@davidbak bu tablodaki konvansiyonel endeksler gerçekten en kötü durumda çok yararlı değildir, çünkü aralığın yarısını taramak zorundadır ve dolayısıyla üzerinde potansiyel iyileştirmeler ister. SQL Server 2000 için "granül" tanıtımı ile bağlantılı soruda hoş bir gelişme var Ben mekansal dizinleri containssorguları destek olarak yardımcı olabilir umuyordum ve onlar iyi okuma veri miktarını azaltmak gibi çalışırken diğer eklemek gibi görünüyor buna karşı ek yük.
Martin Smith

Ben denemek için tesis yok - ama merak ediyorum iki dizin - biri alt sınır, biri üst - ve sonra bir iç birleştirmek - sorgu optimizer bir şey dışarı çalışmasına izin verir.
davidbak

Yanıtlar:


11

Columnstore burada, masanın yarısını tarayan kümelenmemiş bir dizine kıyasla çok acayiptir. Kümelenmemiş bir sütun deposu dizini, avantajın çoğunu sağlar, ancak sıralı verileri kümelenmiş bir sütun deposu dizinine eklemek daha da iyidir.

DROP TABLE IF EXISTS dbo.MyTableCCI;

CREATE TABLE dbo.MyTableCCI
(
Id        INT PRIMARY KEY,
RangeFrom INT NOT NULL,
RangeTo   INT NOT NULL,
CHECK (RangeTo > RangeFrom),
INDEX CCI CLUSTERED COLUMNSTORE
);

INSERT INTO dbo.MyTableCCI
SELECT TOP (987654321) *
FROM dbo.MyTable
ORDER BY RangeFrom ASC
OPTION (MAXDOP 1);

Tasarım gereği, RangeFromsütunlarımda grup gruplarımın yarısını ortadan kaldıracak olan satır grubu eliminasyonu elde edebilirim . Ancak verilerin doğası gereği RangeTosütunda da satır grubu eliminasyonu elde ediyorum :

Table 'MyTableCCI'. Segment reads 1, segment skipped 9.

Daha değişken verilere sahip daha büyük tablolar için, her iki sütunda mümkün olan en iyi satır grubu eliminasyonunu garanti etmek için verileri yüklemenin farklı yolları vardır. Özellikle verileriniz için, sorgu 1 ms sürer.


Evet kesinlikle 2000 kısıtlaması olmadan dikkate alınacak başka yaklaşımlar arıyor. Öyle deđil.
Martin Smith

9

Paul White , Itzik Ben Gan'ın ilginç bir makalesine bağlantı içeren benzer bir sorunun cevabına dikkat çekti . Bu, etkin bir şekilde yapılmasını sağlayan "Statik İlişkisel Aralık Ağacı" modelini tanımlar.

Özetle bu yaklaşım, satırdaki aralık değerlerine dayalı olarak hesaplanan ("forknode") bir değerin saklanmasını içerir. Başka bir aralıkla kesişen aralıklar ararken, eşleşen satırların sahip olması gereken olası çatal düğümü değerlerini önceden hesaplamak ve bunu maksimum 31 arama işlemiyle sonuçları bulmak için kullanabilirsiniz (aşağıda, 0 ile maksimum işaretli 32 arasındaki tamsayıları destekler) bit int)

Buna dayanarak tabloyu aşağıdaki gibi yeniden yapılandırdım.

CREATE TABLE dbo.MyTable3
(
  Id        INT IDENTITY PRIMARY KEY,
  RangeFrom INT NOT NULL,
  RangeTo   INT NOT NULL,   
  node  AS RangeTo - RangeTo % POWER(2, FLOOR(LOG((RangeFrom - 1) ^ RangeTo, 2))) PERSISTED NOT NULL,
  CHECK (RangeTo > RangeFrom)
);

CREATE INDEX ix1 ON dbo.MyTable3 (node, RangeFrom) INCLUDE (RangeTo);
CREATE INDEX ix2 ON dbo.MyTable3 (node, RangeTo) INCLUDE (RangeFrom);

SET IDENTITY_INSERT MyTable3 ON

INSERT INTO MyTable3
            (Id,
             RangeFrom,
             RangeTo)
SELECT Id,
       RangeFrom,
       RangeTo
FROM   MyTable

SET IDENTITY_INSERT MyTable3 OFF 

Ve sonra aşağıdaki sorguyu kullandı (makale kesişen aralıkları arıyor, bu nedenle bir nokta içeren bir aralık bulmak bu dejenere bir durumdur)

DECLARE @value INT = 50000000;

;WITH N AS
(
SELECT 30 AS Level, 
       CASE WHEN @value > POWER(2,30) THEN POWER(2,30) END AS selected_left_node, 
       CASE WHEN @value < POWER(2,30) THEN POWER(2,30) END AS selected_right_node, 
       (SIGN(@value - POWER(2,30)) * POWER(2,29)) + POWER(2,30)  AS node
UNION ALL
SELECT N.Level-1,   
       CASE WHEN @value > node THEN node END AS selected_left_node,  
       CASE WHEN @value < node THEN node END AS selected_right_node,
       (SIGN(@value - node) * POWER(2,N.Level-2)) + node  AS node
FROM N 
WHERE N.Level > 0
)
SELECT I.id, I.RangeFrom, I.RangeTo
FROM dbo.MyTable3 AS I
  JOIN N AS L
    ON I.node = L.selected_left_node
    AND I.RangeTo >= @value
    AND L.selected_left_node IS NOT NULL
UNION ALL
SELECT I.id, I.RangeFrom, I.RangeTo
FROM dbo.MyTable3 AS I
  JOIN N AS R
    ON I.node = R.selected_right_node
    AND I.RangeFrom <= @value
    AND R.selected_right_node IS NOT NULL
UNION ALL
SELECT I.id, I.RangeFrom, I.RangeTo
FROM dbo.MyTable3 AS I
WHERE node = @value;

Bu 1ms, tüm sayfalar önbellekte (ES değerleri ile) makinemde çalışır.

Table 'MyTable3'. Scan count 24, logical reads 72, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 4, logical reads 374, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

ve planla

resim açıklamasını buraya girin

Not: Kaynak, düğümlerin katılmasını sağlamak için özyinelemeli bir CTE yerine çok aşamalı TVF'ler kullanır, ancak cevabımı kendi içinde bulundurma çıkarları için ikincisini seçtim. Prodüksiyon kullanımı için muhtemelen TVF'leri kullanırım.


9

N / CCI yaklaşımıyla rekabetçi bir satır modu yaklaşımı bulabildim, ancak verileriniz hakkında bir şeyler bilmeniz gerekiyor. Eğer farkını içeren bir sütun olduğunu varsayalım RangeFromve RangeTove birlikte onu endeksli RangeFrom:

ALTER TABLE dbo.MyTableWithDiff ADD DiffOfColumns AS RangeTo-RangeFrom;

CREATE INDEX IXDIFF ON dbo.MyTableWithDiff (DiffOfColumns,RangeFrom) INCLUDE (RangeTo);

Tüm farklı değerlerini DiffOfColumnsbiliyorsanız , ilgili verilerin tümünü almak DiffOfColumnsiçin aralık filtresiyle her değer için bir arama yapabilirsiniz RangeTo. Örneğin, DiffOfColumns= 2 olduğunu biliyorsanız, izin verilen tek değer RangeFrom49999998, 49999999 ve 50000000'dir. Özyineleme, tüm farklı değerlerini elde etmek için kullanılabilir DiffOfColumnsve yalnızca 256 tanesi olduğu için veri kümeniz için iyi çalışır. Aşağıdaki sorgu makinemde yaklaşık 6 ms sürüyor:

WITH RecursiveCTE
AS
(
    -- Anchor
    SELECT TOP (1)
        DiffOfColumns
    FROM dbo.MyTableWithDiff AS T
    ORDER BY
        T.DiffOfColumns

    UNION ALL

    -- Recursive
    SELECT R.DiffOfColumns
    FROM
    (
        -- Number the rows
        SELECT 
            T.DiffOfColumns,
            rn = ROW_NUMBER() OVER (
                ORDER BY T.DiffOfColumns)
        FROM dbo.MyTableWithDiff AS T
        JOIN RecursiveCTE AS R
            ON R.DiffOfColumns < T.DiffOfColumns
    ) AS R
    WHERE
        -- Only the row that sorts lowest
        R.rn = 1
)
SELECT ca.*
FROM RecursiveCTE rcte
CROSS APPLY (
    SELECT mt.Id, mt.RangeFrom, mt.RangeTo
    FROM dbo.MyTableWithDiff mt
    WHERE mt.DiffOfColumns = rcte.DiffOfColumns
    AND mt.RangeFrom >= 50000000 - rcte.DiffOfColumns AND mt.RangeFrom <= 50000000
) ca
OPTION (MAXRECURSION 0);

Her farklı değer için dizin arama ile birlikte olağan özyinelemeli bölümü görebilirsiniz:

sorgu planı 1

Bu yaklaşımdaki kusur, çok fazla farklı değer olduğunda yavaşlamaya başlamasıdır DiffOfColumns. Aynı testi yapalım, ama CRYPT_GEN_RANDOM(2)yerine kullanalım CRYPT_GEN_RANDOM(1).

DROP TABLE IF EXISTS dbo.MyTableBigDiff;

CREATE TABLE dbo.MyTableBigDiff
(
Id        INT IDENTITY PRIMARY KEY,
RangeFrom INT NOT NULL,
RangeTo   INT NOT NULL,
CHECK (RangeTo > RangeFrom)
);

WITH RandomNumbers
     AS (SELECT TOP 10000000 ABS(CRYPT_GEN_RANDOM(4)%100000000) AS Num
         FROM   sys.all_objects o1,
                sys.all_objects o2,
                sys.all_objects o3,
                sys.all_objects o4)
INSERT INTO dbo.MyTableBigDiff
            (RangeFrom,
             RangeTo)
SELECT Num,
       Num + 1 + CRYPT_GEN_RANDOM(2) -- note the 2
FROM   RandomNumbers;


ALTER TABLE dbo.MyTableBigDiff ADD DiffOfColumns AS RangeTo-RangeFrom;

CREATE INDEX IXDIFF ON dbo.MyTableBigDiff (DiffOfColumns,RangeFrom) INCLUDE (RangeTo);

Aynı sorgu artık özyinelemeli kısımdan 65536 satır bulur ve makinemde 823 ms CPU alıyor. PAGELATCH_SH bekleme ve diğer kötü şeyler oluyor. Benzersiz değerlerin sayısını kontrol altında tutmak ve içindeki kovalamayı ayarlamak için fark değerlerini gruplandırarak performansı artırabilirim CROSS APPLY. Bu veri seti için 256 kova deneyeceğim:

ALTER TABLE dbo.MyTableBigDiff ADD DiffOfColumns_bucket256 AS CAST(CEILING((RangeTo-RangeFrom) / 256.) AS INT);

CREATE INDEX [IXDIFF😎] ON dbo.MyTableBigDiff (DiffOfColumns_bucket256, RangeFrom) INCLUDE (RangeTo);

(Artık gerçek değer yerine yuvarlanmış bir değerle karşılaştırıyorum) fazla satır almayı önlemenin bir yolu filtrelemektir RangeTo:

CROSS APPLY (
    SELECT mt.Id, mt.RangeFrom, mt.RangeTo
    FROM dbo.MyTableBigDiff mt
    WHERE mt.DiffOfColumns_bucket256 = rcte.DiffOfColumns_bucket256
    AND mt.RangeFrom >= 50000000 - (256 * rcte.DiffOfColumns_bucket256)
    AND mt.RangeFrom <= 50000000
    AND mt.RangeTo >= 50000000
) ca

Tam sorgu şimdi makinemde 6 ms sürüyor.


8

Bir aralığı temsil etmenin alternatif bir yolu, bir çizgideki noktalar olabilir.

Aşağıda tüm veriler, veri geometrytürü olarak gösterilen aralık ile yeni bir tabloya taşınır .

CREATE TABLE MyTable2
(
Id INT IDENTITY PRIMARY KEY,
Range GEOMETRY NOT NULL,
RangeFrom AS Range.STPointN(1).STX,
RangeTo   AS Range.STPointN(2).STX,
CHECK (Range.STNumPoints() = 2 AND Range.STPointN(1).STY = 0 AND Range.STPointN(2).STY = 0)
);

SET IDENTITY_INSERT MyTable2 ON

INSERT INTO MyTable2
            (Id,
             Range)
SELECT ID,
       geometry::STLineFromText(CONCAT('LINESTRING(', RangeFrom, ' 0, ', RangeTo, ' 0)'), 0)
FROM   MyTable

SET IDENTITY_INSERT MyTable2 OFF 


CREATE SPATIAL INDEX index_name   
ON MyTable2 ( Range )  
USING GEOMETRY_GRID  
WITH (  
BOUNDING_BOX = ( xmin=0, ymin=0, xmax=110000000, ymax=1 ),  
GRIDS = (HIGH, HIGH, HIGH, HIGH),  
CELLS_PER_OBJECT = 16); 

Değeri içeren aralıkları bulmak için eşdeğer sorgu 50,000,000aşağıdadır.

SELECT Id,
       RangeFrom,
       RangeTo
FROM   MyTable2
WHERE  Range.STContains(geometry::STPointFromText ('POINT (50000000 0)', 0)) = 1 

Bunun için yapılan okumalar 10,951orijinal sorgudan bir gelişme göstermektedir .

Table 'MyTable2'. Scan count 0, logical reads 505, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'extended_index_1797581442_384000'. Scan count 4, logical reads 17, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Ancak geçen süre bakımından orijinal üzerinde önemli bir gelişme yok . Tipik yürütme sonuçları 250 ms vs 252 ms'dir.

Uygulama planı aşağıdaki gibi daha karmaşıktır

resim açıklamasını buraya girin

Yeniden yazmanın benim için güvenilir bir şekilde daha iyi performans gösterdiği tek durum, soğuk bir önbellektir.

Bu durumda hayal kırıklığı yaratıyor ve bu yeniden yazmayı önermek zor, ancak olumsuz sonuçların yayınlanması da yararlı olabilir.


5

Yeni robot derebeylerimize bir saygı olarak, yeni ish R ve Python işlevlerinden herhangi birinin bize yardımcı olup olamayacağını görmeye karar verdim. Cevap hayır, en azından çalışabileceğim ve doğru sonuçları döndürdüğüm komut dosyaları için. Eğer daha iyi bilgiye sahip olan biri gelirse, beni şaplamaktan çekinmeyin. Benim oranları makul.

Bunu yapmak için, 4 çekirdekli ve 16 GB RAM'li bir VM kurdum, bunun ~ 200MB'lik bir veri seti ile başa çıkmak için yeterli olacağını düşünüyorum.

Boston'da olmayan dille başlayalım!

R,

EXEC sp_execute_external_script 
@language = N'R', 
@script = N'
tweener = 50000000
MO = data.frame(MartinIn)
MartinOut <- subset(MO, RangeFrom <= tweener & RangeTo >= tweener, select = c("Id","RangeFrom","RangeTo"))
', 
@input_data_1_name = N'MartinIn',
@input_data_1 = N'SELECT Id, RangeFrom, RangeTo FROM dbo.MyTable',
@output_data_1_name = N'MartinOut',
@parallel = 1
WITH RESULT SETS ((ID INT, RangeFrom INT, RangeTo INT));

Kötü bir zamandı.

Table 'MyTable'. Scan count 1, logical reads 22400

 SQL Server Execution Times:
   CPU time = 3219 ms,  elapsed time = 5349 ms.

Yürütme planı oldukça orta operatör bize isim aramak zorunda neden bilmiyorum ama, ilginç.

FINDIK

Sıradaki boya kalemi ile kodlama!

piton

EXEC sp_execute_external_script 
@language = N'Python', 
@script = N'
import pandas as pd
MO = pd.DataFrame(MartinIn)
tweener = 50000000
MartinOut = MO[(MO.RangeFrom <= tweener) & (MO.RangeTo >= tweener)]
', 
@input_data_1_name = N'MartinIn',
@input_data_1 = N'SELECT Id, RangeFrom, RangeTo FROM dbo.MyTable',
@output_data_1_name = N'MartinOut',
@parallel = 1
WITH RESULT SETS ((ID INT, RangeFrom INT, RangeTo INT));

Tam olarak R'den daha kötü olamayacağını düşündüğünüzde:

Table 'MyTable'. Scan count 1, logical reads 22400

 SQL Server Execution Times:
   CPU time = 3797 ms,  elapsed time = 10146 ms.

Bir başka kötü ağızlı infaz planı :

FINDIK

Hmm ve Hmmer

Şimdiye kadar etkilenmedim. Bu VM'yi silmek için sabırsızlanıyorum.


1
Parametreleri de aktarabilirsiniz, örneğin, DECLARE @input INT = 50000001; EXEC dbo.sp_execute_external_script @language = N'R', @script = N'OutputDataSet <- InputDataSet[which(x >= InputDataSet$RangeFrom & x <= InputDataSet$RangeTo) , ]', @parallel = 1, @input_data_1 = N'SELECT Id, RangeFrom, RangeTo FROM dbo.MyTable;', @params = N'@x INT', @x = 50000001 WITH RESULT SETS ( ( Id INT NOT NULL, RangeFrom INT NOT NULL, RangeTo INT NOT NULL ));evet performans iyi değil. SQL'de yapamayacağınız şeyler için R kullanıyorum, bir şey tahmin etmek istiyorsanız söyleyin.
wBob

4

Hesaplanmış bir sütun kullanarak oldukça iyi bir çözüm buldum, ancak sadece tek bir değer için iyi. Bununla birlikte, sihirli bir değeriniz varsa, belki de yeterlidir.

Verdiğiniz örnekle başlayıp tabloyu değiştirin:

ALTER TABLE dbo.MyTable
    ADD curtis_jackson 
        AS CONVERT(BIT, CASE 
                            WHEN RangeTo >= 50000000
                            AND RangeFrom < 50000000
                            THEN 1 
                            ELSE 0 
                        END);

CREATE INDEX IX1_redo 
    ON dbo.MyTable (curtis_jackson) 
        INCLUDE (RangeFrom, RangeTo);

Sorgu basitçe şöyle olur:

SELECT *
FROM MyTable
WHERE curtis_jackson = 1;

Bu, başlangıç ​​sorgunuzla aynı sonuçları döndürür. Yürütme planları kapalıyken, istatistikler (kısalık için kısaltılmıştır):

Table 'MyTable'. Scan count 1, logical reads 3...

SQL Server Execution Times:
  CPU time = 0 ms,  elapsed time = 0 ms.

İşte sorgu planı :

FINDIK


Üzerinde bir indeks bulunan hesaplanmış sütun / filtrelenmiş endeksi taklitinin üstesinden gelemez misiniz WHERE (50000000 BETWEEN RangeFrom AND RangeTo) INCLUDE (..)?
ypercubeᵀᴹ

3
@ yper-crazyhat-cubeᵀᴹ - evet. CREATE INDEX IX1_redo ON dbo.MyTable (curtis_jackson) INCLUDE (RangeFrom, RangeTo) WHERE RangeTo >= 50000000 AND RangeFrom <= 50000000çalışır. Ve sorgu SELECT * FROM MyTable WHERE RangeTo >= 50000000 AND RangeFrom <= 50000000;bunu kullanıyor - o zaman fakir Curtis'e çok fazla gerek yok
Martin Smith

3

Benim çözümüm, aralığın bilinen bir maksimum genişliğe W sahip olduğu gözlemine dayanmaktadır . Örnek veriler için bu bir bayt veya 256 tamsayıdır. Bu nedenle, belirli bir arama parametresi P değeri için, sonuç kümesinde bulunabilecek en küçük RangeFrom değerini P - W olarak biliyoruz . Yüklemine yüklem eklemek

declare @P int = 50000000;
declare @W int = 256;

select
    *
from MyTable
where @P between RangeFrom and RangeTo
and RangeFrom >= (@P - @W);

Orijinal kurulum ve benim makine sorgulama (64 bit Windows 10, 4 çekirdekli hiper iş parçacıklı i7, 2.8 GHz, 16 GB RAM) 13 satır döndürür. Bu sorgu, (RangeFrom, RangeTo) dizinine paralel dizin araması kullanır. Gözden geçirilmiş sorgu aynı dizinde paralel bir dizin araması da gerçekleştirir.

Orijinal ve gözden geçirilmiş sorguların ölçümleri

                          Original  Revised
                          --------  -------
Stats IO Scan count              9        6
Stats IO logical reads       11547        6

Estimated number of rows   1643170  1216080
Number of rows read        5109666       29
QueryTimeStats CPU             344        2
QueryTimeStats Elapsed          53        0

Orijinal sorgu için, okunan satır sayısı @P'den küçük veya ona eşit olan satır sayısına eşittir. Sorgu iyileştiricinin (QO) alternatifi yoktur, ancak bu satırların yüklemi karşılayacağını önceden belirleyemediği için hepsini okuyabilirsiniz. (RangeFrom, RangeTo) üzerindeki çok sütunlu dizin, birinci dizin anahtarı ile uygulanabilecek ikincisi arasında korelasyon olmadığından RangeTo ile eşleşmeyen satırların kaldırılmasında yararlı değildir. Örneğin, ilk sıranın küçük bir aralığı olabilir ve elimine edilebilirken, ikinci sıranın geniş bir aralığı vardır ve döndürülür, ya da tam tersi.

Başarısız olan bir denemede bu kesinliği kontrol kısıtlamasıyla sağlamaya çalıştım:

alter table MyTable with check
add constraint CK_MyTable_Interval
check
(
    RangeTo <= RangeFrom + 256
);

Hiçbir fark yaratmadı.

Veri dağıtımı hakkındaki dış bilgimi yükleme dahil ederek, QO'nun asla sonuç kümesinin bir parçası olamayacak ve endeksin önde gelen sütununu kabul edilebilir satırlara geçirebilecek düşük değerli RangeFrom satırlarını atlamasına neden olabilirim. Bu, her sorgu için farklı arama yüklemini gösterir.

Bir ayna argümanında RangeTo'nun üst sınırı P + W'dir . Ancak bu yararlı değildir, çünkü RangeFrom ve RangeTo arasında çok sütunlu bir dizinin sondaki sütunun satırları ortadan kaldırmasına izin verecek bir korelasyon yoktur. Bu nedenle, bu maddeyi sorguya eklemenin bir yararı yoktur.

Bu yaklaşım faydasının çoğunu küçük aralık büyüklüğünden kazanır. Olası aralık boyutu arttıkça, atlanan düşük değerli satırların sayısı azalır, ancak bazıları hala atlanacaktır. Sınırlayıcı durumda, veri aralığı kadar büyük bir aralıkta, bu yaklaşım orijinal sorgudan (kabul ettiğim soğuk konfor) daha kötü değildir.

Bu cevapta olabilecek hatalar için özür dilerim.

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.