Performa In-Memory Table lebih buruk daripada tabel berbasis disk

10

Saya punya tabel di SQL Server 2014 yang terlihat seperti berikut:

CREATE TABLE dbo.MyTable
(
[id1] [bigint] NOT NULL,
[id2] [bigint] NOT NULL,
[col1] [int] NOT NULL default(0),
[col2] [int] NOT NULL default(0)
)

dengan (id1, id2) menjadi PK. Pada dasarnya, id1 adalah pengidentifikasi untuk mengelompokkan serangkaian hasil (id2, col1, col2), yang pknya adalah id2.

Saya mencoba menggunakan tabel di-memori untuk menyingkirkan tabel berbasis disk yang ada yang menjadi hambatan saya.

  • Data dalam tabel ditulis -> dibaca -> dihapus sekali.
  • Setiap nilai id1 memiliki beberapa (puluhan / ratusan) ribuan id2.
  • Data disimpan dalam tabel untuk waktu yang sangat singkat, misalnya 20 detik.

Pertanyaan yang dilakukan pada tabel ini adalah sebagai berikut:

-- INSERT (can vary from 10s to 10,000s of records):
INSERT INTO MyTable
  SELECT @fixedValue, id2, col1, col2 FROM AnotherTable

-- READ:
SELECT id2, col1
FROM MyTable INNER JOIN OtherTbl ON MyTable.id2 = OtherTbl.pk
WHERE id1 = @value
ORDER BY col1

-- DELETE:
DELETE FROM MyTable WHERE id1 = @value

Inilah definisi saat ini yang saya gunakan untuk tabel:

CREATE TABLE dbo.SearchItems
(
  [id1] [bigint] NOT NULL,
  [id2] [bigint] NOT NULL,
  [col1] [int] NOT NULL default(0),
  [col2] [int] NOT NULL default(0)

  CONSTRAINT PK_Mem PRIMARY KEY NONCLUSTERED (id1,id2),
  INDEX idx_Mem HASH (id1,id2) WITH (BUCKET_COUNT = 131072)
) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY)

Sayangnya, definisi ini menghasilkan penurunan kinerja sehubungan dengan situasi sebelumnya dengan tabel berbasis disk. Urutan besarnya lebih atau kurang 10% lebih tinggi (yang dalam beberapa kasus mencapai 100%, jadi dua kali lipat).

Yang paling utama, saya mengharapkan untuk mendapatkan keuntungan super dalam skenario konkurensi tinggi, mengingat arsitektur bebas kunci yang diiklankan oleh Microsoft. Sebagai gantinya, kinerja terburuk adalah persis ketika ada beberapa pengguna bersamaan menjalankan beberapa pertanyaan di atas meja.

Pertanyaan:

  • berapa BUCKET_COUNT yang benar untuk ditetapkan?
  • indeks apa yang harus saya gunakan?
  • mengapa kinerjanya lebih buruk daripada dengan tabel berbasis disk?

Kueri sys.dm_db_xtp_hash_index_stats kembali:

total_bucket_count = 131072
empty_bucket_count = 0
avg_chain_len = 873
max_chain_length = 1009

Saya mengubah jumlah bucket sehingga output dari sys.dm_db_xtp_hash_index_stats adalah:

total_bucket_count = 134217728
empty_bucket_count = 131664087
avg_chain_len = 1
max_chain_length = 3

Meski begitu, hasilnya hampir sama, jika tidak lebih buruk.

Cristiano Ghersi
sumber
Apakah Anda yakin tidak menjalankan sniffing parameter? Sudahkah Anda mencoba menjalankan kueri dengan OPTION(OPTIMIZE FOR UNKNOWN)(lihat Tabel Petunjuk )?
TT.
Dugaan saya adalah Anda mengalami masalah rantai baris. Bisakah Anda memberi kami hasil select * from sys.dm_db_xtp_hash_index_stats ? Juga, tautan ini harus menjawab sebagian besar / semua pertanyaan Anda: msdn.microsoft.com/en-us/library/…
Sean Gallardy
4
Indeks hash hanya berguna untuk predikat pada kedua kolom yang disertakan. Sudahkah Anda mencoba tanpa indeks hash di atas meja?
Mikael Eriksson
Saya telah menemukan bahwa peningkatan kinerja terbaik dengan teknologi dalam memori hanya dapat dicapai dengan menggunakan prosedur tersimpan yang disusun secara asli .
Daniel Hutmacher
@DanielHutmacher FWIW Saya telah melihat contoh tandingan di mana semua manfaatnya adalah melepas kait dan menambahkan prosedur yang dikompilasi secara alami memberi peningkatan nol atau diabaikan. Saya tidak berpikir ada ruang untuk pernyataan selimut (meskipun Anda mungkin benar dalam kasus ini, saya bahkan belum melihat detailnya).
Aaron Bertrand

Jawaban:

7

Meskipun posting ini tidak akan menjadi jawaban yang lengkap karena kekurangan informasi, pos ini seharusnya dapat mengarahkan Anda ke arah yang tepat atau mendapatkan wawasan yang nantinya dapat Anda bagikan dengan komunitas.

Sayangnya, definisi ini menghasilkan penurunan kinerja sehubungan dengan situasi sebelumnya dengan tabel berbasis disk. Urutan besarnya lebih atau kurang 10% lebih tinggi (yang dalam beberapa kasus mencapai 100%, jadi dua kali lipat).

Yang paling utama, saya mengharapkan untuk mendapatkan keuntungan super dalam skenario konkurensi tinggi, mengingat arsitektur bebas kunci yang diiklankan oleh Microsoft. Sebagai gantinya, kinerja terburuk adalah persis ketika ada beberapa pengguna bersamaan menjalankan beberapa pertanyaan di atas meja.

Ini menyusahkan karena seharusnya tidak demikian. Beban kerja tertentu tidak untuk dalam tabel memori (SQL 2014) dan beberapa beban kerja sesuai untuk itu. Dalam sebagian besar situasi mungkin ada sedikit peningkatan kinerja hanya dengan bermigrasi dan memilih indeks yang tepat.

Awalnya saya berpikir sangat sempit tentang pertanyaan Anda mengenai hal ini:

Pertanyaan:

  • berapa BUCKET_COUNT yang benar untuk ditetapkan?
  • indeks apa yang harus saya gunakan?
  • mengapa kinerjanya lebih buruk daripada dengan tabel berbasis disk?

Awalnya saya percaya akan ada masalah dengan aktual dalam tabel memori dan indeks tidak optimal. Meskipun ada beberapa masalah dengan memori yang dioptimalkan definisi indeks hash saya percaya masalah sebenarnya adalah dengan pertanyaan yang digunakan.

-- INSERT (can vary from 10s to 10,000s of records):
INSERT INTO MyTable
  SELECT @fixedValue, id2, col1, col2 FROM AnotherTable

Sisipan ini harus sangat cepat jika hanya melibatkan tabel memori. Namun, ini juga melibatkan tabel berbasis disk dan tunduk pada semua penguncian dan pemblokiran yang terkait dengannya. Dengan demikian, pemborosan waktu nyata di sini adalah pada tabel berbasis disk.

Ketika saya melakukan tes cepat terhadap 100.000 baris memasukkan dari tabel berbasis disk setelah memuat data ke dalam memori - itu adalah waktu respon sub-detik. Namun, sebagian besar data Anda hanya disimpan untuk waktu yang sangat singkat, kurang dari 20 detik. Ini tidak memberikan banyak waktu untuk benar-benar hidup dalam cache. Selain itu saya tidak yakin seberapa besar AnotherTablesebenarnya dan tidak tahu apakah nilai sedang dibaca dari disk atau tidak. Kami harus mengandalkan Anda untuk jawaban ini.

Dengan kueri Select:

SELECT id2, col1
FROM MyTable INNER JOIN OtherTbl ON MyTable.id2 = OtherTbl.pk
WHERE id1 = @value
ORDER BY col1

Sekali lagi, kita berada di tangan kinerja tabel berbasis disk + interop. Selain itu, jenis tidak murah pada indeks HASH dan indeks nonclustered harus digunakan. Ini disebut dalam panduan Indeks yang saya tautkan dalam komentar.

Untuk memberikan beberapa fakta berdasarkan penelitian aktual, saya memuat SearchItemstabel memori dengan 10 juta baris dan AnotherTabledengan 100.000 karena saya tidak tahu ukuran aktual atau statistiknya. Saya kemudian menggunakan kueri pemilihan di atas untuk mengeksekusi. Selain itu saya membuat sesi acara diperpanjang pada wait_completed dan memasukkannya ke dalam buffer cincin. Itu dibersihkan setelah setiap kali dijalankan. Saya juga berlari DBCC DROPCLEANBUFFERSuntuk mensimulasikan lingkungan di mana semua data mungkin bukan memori.

Hasilnya bukanlah sesuatu yang spektakuler ketika melihatnya dalam ruang hampa. Karena laptop yang saya uji ini menggunakan SSD kelas yang lebih tinggi, saya secara artifisial menurunkan kinerja berbasis disk untuk VM yang saya gunakan.

Hasilnya masuk tanpa info tunggu setelah 5 kali menjalankan kueri hanya pada tabel berbasis di-memori (menghapus gabungan dan tidak ada sub-kueri). Ini seperti yang diharapkan.

Namun, saat menggunakan kueri asli, saya sudah menunggu. Dalam hal ini adalah PAGEIOLATCH_SH yang masuk akal karena data sedang dibaca dari disk. Karena saya adalah satu - satunya pengguna dalam sistem ini dan tidak menghabiskan waktu untuk membuat lingkungan pengujian besar-besaran untuk memasukkan, memperbarui, menghapus terhadap tabel yang digabungkan, saya tidak mengharapkan penguncian atau pemblokiran mulai berlaku.

Dalam hal ini, sekali lagi, sebagian besar waktu dihabiskan di atas meja berbasis disk.

Akhirnya kueri penghapusan. Menemukan baris berdasarkan hanya ID1 tidak sangat efisien dengan indeks has. Meskipun benar bahwa predikat kesetaraan adalah indeks hash yang tepat untuknya, bucket yang digunakan untuk memasukkan data didasarkan pada seluruh kolom hash. Jadi id1, id2 di mana id1 = 1, id2 = 2, dan id1 = 1, id2 = 3 akan hash ke dalam ember yang berbeda seperti hash akan melintasi (1,2) dan (1,3). Ini tidak akan menjadi pemindaian rentang B-Tree sederhana karena indeks hash tidak terstruktur dengan cara yang sama. Saya kemudian berharap ini bukan indeks yang ideal untuk operasi ini, namun saya tidak akan mengharapkannya untuk mengambil pesanan yang lebih besar seperti yang dialami. Saya akan tertarik melihat wait_info tentang ini.

Yang paling utama, saya mengharapkan untuk mendapatkan keuntungan super dalam skenario konkurensi tinggi, mengingat arsitektur bebas kunci yang diiklankan oleh Microsoft. Sebagai gantinya, kinerja terburuk adalah persis ketika ada beberapa pengguna bersamaan menjalankan beberapa pertanyaan di atas meja.

Meskipun benar bahwa kunci digunakan untuk konsistensi logis, operasi masih harus atom. Hal ini dilakukan melalui operator pembanding berbasis CPU khusus (itulah sebabnya In-Memory hanya bekerja dengan prosesor [meskipun hampir semua CPU yang dibuat dalam 4 tahun terakhir] prosesor). Jadi kami tidak mendapatkan semuanya secara gratis, masih ada waktu untuk menyelesaikan operasi ini.

Hal lain yang perlu dikemukakan adalah kenyataan bahwa di hampir semua kueri, antarmuka yang digunakan adalah T-SQL (dan tidak secara alami mengkompilasi SPROCs) yang semuanya menyentuh setidaknya satu tabel berbasis disk. Inilah sebabnya saya percaya, pada akhirnya, kami tidak benar-benar mengalami peningkatan kinerja karena kami masih terkendala dengan kinerja tabel berbasis disk.

Mengikuti:

  1. Buat sesi acara diperpanjang untuk wait_completed dan tentukan SPID yang Anda kenal. Jalankan kueri dan beri kami output atau konsumsi secara internal.

  2. Beri kami pembaruan pada output dari # 1.

  3. Tidak ada angka ajaib untuk menentukan jumlah bucket untuk indeks hash. Pada dasarnya selama ember tidak sepenuhnya penuh dan rantai baris tetap di bawah 3 atau 4, kinerja harus tetap dapat diterima. Ini seperti bertanya, "Apa yang harus saya atur file log saya?" - itu akan tergantung per proses, per database, per jenis penggunaan.

Sean Gallardy
sumber