Birincil anahtarda belirtilen sıralama düzeni, ancak sıralama SELECT'te yürütüldü


15

Sensör verilerini SensorValues tablosunda saklıyorum . Tablo ve birincil anahtar aşağıdaki gibidir:

CREATE TABLE [dbo].[SensorValues](
  [DeviceId] [int] NOT NULL,
  [SensorId] [int] NOT NULL,
  [SensorValue] [int] NOT NULL,
  [Date] [int] NOT NULL,
CONSTRAINT [PK_SensorValues] PRIMARY KEY CLUSTERED 
(
  [DeviceId] ASC,
  [SensorId] ASC,
  [Date] DESC
) WITH (
    FILLFACTOR=75,
    DATA_COMPRESSION = PAGE,
    PAD_INDEX = OFF,
    STATISTICS_NORECOMPUTE = OFF,
    SORT_IN_TEMPDB = OFF,
    IGNORE_DUP_KEY = OFF,
    ONLINE = OFF,
    ALLOW_ROW_LOCKS = ON,
    ALLOW_PAGE_LOCKS = ON)
  ON [MyPartitioningScheme]([Date])

Ancak, belirli bir süre için geçerli olan sensör değerini seçtiğimde, yürütme planı bana bunun bir tür iş yaptığını söylüyor. Neden?

Tarih sütununa göre sıralanmış değerleri sakladığım için sıralama oluşmayacağını düşünürdüm. Yoksa, dizin yalnızca Tarih sütununa göre sıralanmadığı için mi, yani sonuç kümesinin sıralandığını varsayamaz mı?

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC

Yürütme planı

Düzenleme: Bunun yerine bunu yapabilir miyim?

Tablo DeviceId, SensorId, Date ve ben olarak sıralandığından, yalnızca bir DeviceId ve bir SensorId belirten bir SELECT yaparız , çıktı kümesi zaten Date DESC'e göre sıralanmalıdır . Yani merak ediyorum ki aşağıdaki soru her durumda aynı sonucu verir mi?

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010

Aşağıdaki @Catcall'a göre, sıralama düzeni depolama siparişiyle aynı değildir. Yani, döndürülen değerlerin zaten sıralanmış bir sırada olduğunu varsayamayız.

Düzenleme: Bu ÇAPRAZ UYGULAMA çözümünü denedim, şans yok

@Martin Smith, sonuçları bölümlere karşı DIŞI UYGULAMAYA çalışmayı önerdi. Bu benzer sorunu açıklayan bir blog yazısı ( bölümlenmiş tablodaki kümelenmemiş dizinleri hizalandı) buldum ve Smith'in önerdiğine biraz benzer bir çözüm denedim. Ancak, burada şans yok, yürütme süresi orijinal çözümümle eşit.

WITH Boundaries(boundary_id)
AS
(
  SELECT boundary_id
  FROM sys.partition_functions pf
  JOIN sys.partition_range_values prf ON pf.function_id = prf.function_id
  WHERE pf.name = 'PF'
  AND prf.value <= 1339225010
  UNION ALL
  SELECT max(boundary_id) + 1
  FROM sys.partition_functions pf
  JOIN sys.partition_range_values prf ON pf.function_id = prf.function_id
  WHERE pf.name = 'PF'
  AND prf.value <= 1339225010
),
Top1(SensorValue)
AS
(
  SELECT TOP 1 d.SensorValue
  FROM Boundaries b
  CROSS APPLY
  (
    SELECT TOP 1 SensorValue
      FROM SensorValues
      WHERE  SensorId = 53
        AND DeviceId = 3819
        AND "Date" < 1339225010
        AND $Partition.PF(Date) = b.boundary_id
        ORDER BY Date DESC
  ) d
  ORDER BY d.Date DESC
)
SELECT SensorValue
FROM Top1

SEÇENEK MAXDOP 1 yardımcı olmaz. Aşağıdaki @ Martin Smith tarafından belirtildiği gibi, bölümleme buna neden olan şey gibi görünüyor ...
m__

Yanıtlar:


13

Bölümlenmemiş bir tablo için aşağıdaki planı alıyorum

Plan 1

Üzerinde tek bir arama yüklemi var Seek Keys[1]: Prefix: DeviceId, SensorId = (3819, 53), Start: Date < 1339225010.

SQL Server bir eşitlik ilk iki sütun üzerinde arama yapabilir ve daha sonra başlayan bir dizi seek başlaması Anlamı 1339225010ve sipariş FORWARD(endeks ile tanımlanır olarak [Date] DESC)

TOPİlk satır yayılan sonra aramaya gelen operatör daha fazla satır talep eden duracaktır.

Bölüm şemasını ve işlevini oluşturduğumda

CREATE PARTITION FUNCTION PF (int)
AS RANGE LEFT FOR VALUES (1000, 1339225009 ,1339225010 , 1339225011);
GO
CREATE PARTITION SCHEME [MyPartitioningScheme]
AS PARTITION PF
ALL TO ([PRIMARY] );

Ve tabloyu aşağıdaki verilerle doldurun

INSERT INTO [dbo].[SensorValues]    
/*500 rows matching date and SensorId, DeviceId predicate*/
SELECT TOP (500) 3819,53,1, ROW_NUMBER() OVER (ORDER BY (SELECT 0))           
FROM master..spt_values
UNION ALL
/*700 rows matching date but not SensorId, DeviceId predicate*/
SELECT TOP (700) 3819,52,1, ROW_NUMBER() OVER (ORDER BY (SELECT 0))           
FROM master..spt_values
UNION ALL 
/*1100 rows matching SensorId, DeviceId predicate but not date */
SELECT TOP (1100) 3819,53,1, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) + 1339225011      
FROM master..spt_values

SQL Server 2008'deki plan aşağıdaki gibidir.

Plan 2

Aramadan yayılan gerçek satır sayısı 500. Plan arama tahminlerini gösteriyor

Seek Keys[1]: Start: PtnId1000 <= 2, End: PtnId1000 >= 1, 
Seek Keys[2]: Prefix: DeviceId, SensorId = (3819, 53), Start: Date < 1339225010

Burada açıklanan atlama tarama yaklaşımını kullandığını belirtmek

sorgu iyileştirici, PartitionID'de (mantıksal öncü sütun olarak) ve muhtemelen diğer dizin anahtar sütunlarında bir koşulu olan bir arama veya tarama işleminin yapılabilmesi ve daha sonra farklı bir koşula sahip ikinci düzey bir arama yapılabilmesi için genişletilir. bir veya daha fazla ek sütunda, birinci düzey arama işlemi için yeterliliği karşılayan her farklı değer için.

Bu plan bir seri plan ve böylece belirli bir sorgu için SQL Server bölümleri azalan sırada dateorijinal plan TOPhala işe yarayacak şekilde işledi ve bu ilk eşleşen satır sonra işleme durabilir gibi görünüyor kalan 499 karşılaşmaya devam etmek ve çıktı almak yerine bulundu.

Aslında 2005'teki plan bu yaklaşımı benimsiyor gibi görünüyor

2005 planı

2008 tarihinde aynı planı almak için yalındır ya da belki bir ihtiyaç olsaydı emin değilim OUTER APPLYüzerine sys.partition_range_valuesonu taklit etmek.



9

Bir çok insan, kümelenmiş bir endeksin çıktı konusunda bir çeşit düzeni garanti ettiğine inanmaktadır . Ama öyle değil; diskte bir depolama siparişini garanti eder .

Örneğin, bu blog gönderisine ve bu daha uzun tartışmaya bakın .


1
Daha önce, OP ayrıca, "Tarih sütununa göre sıralanan değerleri sakladığımdan, sıralamanın [sic] gerçekleşmeyeceğini düşünürdüm" dedi. Bu nedenle, sorunun en azından bir kısmı, kümelenmiş bir dizinin ne yaptığı hakkındaki yanlış anlamadır. Zaten bunu düzeltmek iyi bir şey.
Mike Sherrill 'Cat Recall'

Belki sadece inatçıyım (bu yüzden lütfen beni affet ;-)). Her neyse, Hugo Kornelis'in blog gönderisini okudum ve oldukça basit. Bununla birlikte, örneğinde bir kümelenmiş dizin ve bir kümelenmemiş dizin kullanıyor, kümelenmemiş dizin daha küçüktür ve bu nedenle yürütme planında kullanılmaktadır. Benim durumumda sadece bir kümelenmiş dizin var, sql sunucusu yine de değerleri yanlış sırayla döndürebilir (kullanmak için daha küçük bir dizin yok ve tam tablo taramalar çok yavaş)?
m__

Bunu yeni bir soruya (konu dışı)
taşıdım

5

SIRALA'nın paralel plan nedeniyle gerekli olduğunu tahmin ediyorum. Bunu bazı loş ve uzak blog makalelerine dayandırıyorum: ancak bunu MSDN'de buldum , bunu haklı çıkartabilir veya olmayabilir

MAXDOP 1 ile deneyin ve neler olduğunu görün ...

Ayrıca "Exchange Operatörü" altında Simple Talk üzerine @sql kiwi blog yazısı ima ima . Ve burada "DOP bağımlılığı"


Her ne kadar daha dateönce bir bölüm işlevi ayarlamak rahatsız olmasaydı . Şimdi var ve bölümleme 2005 ile bu özel sorgu için muhtemelen daha iyi davranıyor suçlu var gibi görünüyor.
Martin Smith

1

Temelde haklısınız - birincil anahtar "DeviceId, SensorId, Date" düzeninde olduğundan, anahtardaki veriler tarihe göre sıralanmadığından kullanılamaz. Anahtar farklı bir düzen olsaydı "Tarih, deviceId SensorId", daha sonra anahtar verileri ediyorum bu yüzden kullanılabilir tarihe göre sıralanabilir ...


Zaten bahsettiğiniz şekilde anahtarı değiştirmeyi denemiştim, bu yüzden üzülmeyin. Her neyse, kümelenmemiş dizini 3 sütunun tamamında oluşturmaya çalışacak ve bana ne verdiğini görecek. (eksik endeks arayışı devam ediyor ... ;-))
m__
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.