Urutkan urutan yang ditentukan dalam kunci utama, namun penyortiran dilakukan pada SELECT

15

Saya menyimpan data sensor dalam tabel Nilai Sensor . Tabel dan kunci utama adalah sebagai berikut:

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])

Namun, ketika saya memilih nilai sensor yang valid untuk waktu tertentu, rencana eksekusi memberitahu saya itu sedang melakukan semacam. Mengapa demikian?

Saya akan berpikir bahwa karena saya menyimpan nilai yang diurutkan berdasarkan kolom Date, pengurutan tidak akan terjadi. Atau apakah itu karena indeks tidak hanya diurutkan berdasarkan kolom Tanggal, artinya tidak dapat berasumsi bahwa set hasil diurutkan?

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

Rencana eksekusi

Sunting: Bisakah saya melakukan ini?

Karena tabel diurutkan DeviceId, SensorId, Date dan saya melakukan SELECT menentukan hanya satu DeviceId dan satu SensorId , output yang ditetapkan harus sudah diurutkan berdasarkan Date DESC . Jadi saya bertanya-tanya apakah pertanyaan berikut akan menghasilkan hasil yang sama dalam semua kasus?

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

Menurut @Catcall di bawah ini, urutan pengurutan tidak sama dengan urutan penyimpanan. Yaitu kita tidak dapat mengasumsikan bahwa nilai yang dikembalikan sudah dalam urutan diurutkan.

Sunting: Saya sudah mencoba solusi CROSS APPLY ini, tidak berhasil

@ Martin Smith menyarankan saya akan mencoba LUAR MENERAPKAN hasil saya terhadap partisi. Saya menemukan posting blog ( Indeks non-clustered disejajarkan pada tabel dipartisi ) menggambarkan masalah yang sama dan mencoba solusi yang agak mirip dengan apa yang disarankan Smith. Namun, tidak beruntung di sini, waktu eksekusi setara dengan solusi asli saya.

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
m__
sumber
OPSI MAXDOP 1 tidak membantu. Seperti yang ditentukan oleh @Martin Smith di bawah ini, sepertinya partisi itulah yang menyebabkannya ...
m__

Jawaban:

13

Untuk tabel yang tidak dipartisi saya mendapatkan paket berikut

Paket 1

Ada satu predikat pencarian Seek Keys[1]: Prefix: DeviceId, SensorId = (3819, 53), Start: Date < 1339225010.

Berarti SQL Server dapat melakukan pencarian kesetaraan pada dua kolom pertama dan kemudian mulai mencari rentang mulai dari 1339225010dan dipesan FORWARD(karena indeks didefinisikan dengan [Date] DESC)

The TOPOperator akan berhenti meminta lebih baris dari mencari setelah baris pertama dipancarkan.

Ketika saya membuat skema dan fungsi partisi

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] );

Dan isi tabel dengan data berikut

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

Paket SQL Server 2008 terlihat sebagai berikut.

Paket 2

Jumlah baris aktual yang dipancarkan dari pencarian adalah 500. Rencana menunjukkan mencari predikat

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

Mengindikasikan itu menggunakan pendekatan skip scan yang dijelaskan di sini

optimizer permintaan diperluas sehingga operasi pencarian atau pemindaian dengan satu kondisi dapat dilakukan pada PartitionID (sebagai kolom utama yang logis) dan mungkin kolom kunci indeks lainnya, dan kemudian pencarian tingkat kedua, dengan kondisi yang berbeda, dapat dilakukan pada satu atau lebih kolom tambahan, untuk setiap nilai berbeda yang memenuhi kualifikasi untuk operasi pencarian tingkat pertama.

Paket ini adalah paket serial dan jadi untuk permintaan khusus Anda memilikinya tampaknya jika SQL Server memastikan bahwa ia memproses partisi dalam urutan menurun dari datepaket asli dengan TOPmasih akan bekerja dan bisa berhenti memproses setelah baris pencocokan pertama adalah ditemukan daripada melanjutkan dan menghasilkan 499 sisa pertandingan.

Sebenarnya rencana tahun 2005 sepertinya mengambil pendekatan itu

Rencanakan tahun 2005

Saya tidak yakin apakah itu lurus ke depan untuk mendapatkan rencana yang sama pada 2008 atau mungkin perlu OUTER APPLYon sys.partition_range_valuesuntuk mensimulasikannya.

Martin Smith
sumber
9

Banyak orang percaya bahwa indeks berkerumun menjamin urutan pengurutan pada output. Tapi bukan itu yang dilakukannya; itu menjamin pesanan penyimpanan pada disk.

Lihat, misalnya, posting blog ini , dan diskusi yang lebih panjang ini .

Mike Sherrill 'Cat Recall'
sumber
1
Nah, sebelumnya, OP juga berkata, "Saya akan berpikir bahwa karena saya menyimpan nilai yang diurutkan berdasarkan kolom Date, pengurutan tidak akan terjadi [sic]." Jadi, setidaknya bagian dari masalah adalah kesalahpahaman tentang apa yang dilakukan indeks berkerumun. Saya pikir itu baik untuk meluruskan hal itu.
Mike Sherrill 'Cat Recall'
Mungkin saya hanya keras kepala (jadi tolong maafkan saya ;-)). Bagaimanapun, saya sudah membaca posting blog oleh Hugo Kornelis dan itu cukup mudah. Namun, dalam contohnya dia menggunakan satu indeks berkerumun dan satu non-berkerumun, indeks non-berkerumun lebih kecil dalam ukuran dan dengan demikian digunakan dalam rencana pelaksanaan. Dalam kasus saya, saya hanya memiliki satu indeks berkerumun, bisakah sql server masih mengembalikan nilai dalam urutan yang salah (tidak memiliki indeks yang lebih kecil untuk digunakan dan pemindaian tabel penuh terlalu lambat)?
m__
Saya telah memindahkan ini ke pertanyaan baru (di luar topik)
m__
5

Saya berspekulasi bahwa SORT diperlukan karena rencana paralel. Saya mendasarkan ini pada beberapa artikel blog redup dan jauh: tapi saya menemukan ini di MSDN yang mungkin atau mungkin tidak membenarkan ini

Jadi, coba dengan MAXDOP 1 dan lihat apa yang terjadi ...

Juga mengisyaratkan di dalam posting blog kiwi @sql di Talk Sederhana di bawah "Operator Exchange" saya pikir. Dan "ketergantungan DOP" di sini

gbn
sumber
Meskipun saya tidak repot mengatur fungsi partisi datesebelumnya. Sekarang saya telah dan sepertinya mempartisi adalah penyebab 2005 mungkin berperilaku lebih baik untuk permintaan khusus ini.
Martin Smith
1

Pada dasarnya Anda benar - karena kunci utama dalam urutan "DeviceId, SensorId, Date", data dalam kunci tersebut tidak diurutkan berdasarkan tanggal, jadi tidak dapat digunakan. Jika kunci Anda berada dalam urutan berbeda "Date, DeviceId, SensorId", maka data dalam kunci tersebut akan diurutkan berdasarkan tanggal, sehingga dapat digunakan ...


sumber
Saya sudah mencoba mengubah kunci seperti yang Anda sebutkan, jadi jangan merasa menyesal. Pokoknya, akan mencoba membuat indeks non-cluster di semua 3 kolom dan melihat apa yang memberi saya. (pencarian untuk indeks yang hilang berlanjut ... ;-))
m__