Seleksi Indeks Clustered - PK atau FK?

11

Saya memiliki tabel SQL Server 2014 yang terlihat seperti berikut:

OrderId     int           not null IDENTITY --this is the primary key column
OrderDate   datetime2     not null
CustomerId  int           not null
Description nvarchar(255) null

Beberapa orang di tim saya menyarankan agar indeks berkerumun berada di OrderId, tetapi saya pikir CustomerId+ OrderIdakan menjadi pilihan yang lebih baik karena alasan berikut:

  • Hampir semua pertanyaan akan dicari WHERE CustomerId = @param, bukanOrderId
  • CustomerIdadalah kunci asing ke Customertabel, sehingga memiliki indeks berkerumun dengan CustomerIdharus mempercepat bergabung
  • Meskipun CustomerIdtidak unik, memiliki OrderIdkolom tambahan yang ditentukan dalam indeks akan memastikan keunikan (Kami dapat menggunakan UNIQUEkata kunci saat membuat indeks berkerumun di 2 kolom tersebut, untuk menghindari biaya tambahan karena tidak memiliki keunikan)
  • Setelah data dimasukkan, CustomerIddan OrderIdtidak pernah berubah, jadi baris ini tidak akan bergerak setelah penulisan awal.
  • Akses data terjadi melalui ORM yang meminta semua kolom secara default, jadi ketika kueri berdasarkan CustomerIdmasuk, indeks berkerumun akan dapat menyediakan semua kolom tanpa pekerjaan tambahan.

Apakah pendekatan CustomerIddan OrderIdterdengar seperti opsi terbaik yang diberikan di atas? Atau, apakah OrderIddengan sendirinya lebih baik, karena itu adalah satu kolom yang menjamin keunikan dengan sendirinya?

Saat ini, tabel memiliki indeks berkerumun di OrderId, dan indeks nonclustered aktif CustomerId, tapi itu tidak mencakup, jadi karena kita menggunakan ORM dan semua kolom diminta, itu pekerjaan tambahan untuk mengambilnya. Jadi dengan posting ini, saya mencoba mempertimbangkan untuk meningkatkan kinerja dengan CI yang lebih baik.

Aktivitas pada DB kami sekitar 85% dibaca dan 15% ditulis.

Andy
sumber

Jawaban:

5

Jawaban wiki komunitas :

Saya pikir kunci indeks berkerumun komposit dengan CustomerID sebagai kolom pertama akan menjadi yang terbaik karena itu ada di WHEREklausa hampir semua pertanyaan.

Mungkin ada lebih banyak pemisahan dibandingkan dengan kunci tambahan (atau kemungkinan kerapatan halaman kurang optimal untuk suatu waktu jika Anda mengelola dan mempertahankan faktor isian untuk menghindari pemisahan 'buruk'). Namun, peningkatan kinerja keseluruhan untuk permintaan pelanggan sangat besar, karena pencarian kunci dihindari.

OrderID atau OrderDate mungkin yang terbaik untuk kolom kedua tergantung pada pertanyaan paling kritis Anda.

Misalnya, jika pelanggan melihat daftar kronologis pesanan terbaru setelah masuk ke situs web, OrderDate harus menjadi yang berikutnya, untuk mengoptimalkan ORDER BY OrderDate DESC.

Jika Anda memilih OrderID sebagai indeks berkerumun, dengan indeks non-berkerumun di CustomerID , Anda masih akan mendapatkan pemisahan dan fragmentasi, hanya dalam indeks yang tidak berkerumun.

pengguna126897
sumber
3

Jika tabel ini sangat intensif menulis (misal, lebih banyak INSERTpernyataan muncul daripada SELECTpernyataan yang menentangnya), saya tidak akan setuju dengan jawaban wiki .

Memilih CustomerID sebagai kolom pertama dari kunci berkerumun komposit akan menghasilkan banyak pemisahan halaman tengah . Mudah-mudahan Anda memiliki banyak pelanggan yang sudah ada dan juga mendapatkan banyak pelanggan baru setiap saat. Karena pelanggan (semoga) menempatkan banyak pesanan saat bisnis Anda terus tumbuh, pendekatan ini akan menunjukkan sejumlah besar pemisahan halaman tengah yang akan mematikan kinerja tidak hanya pada saat menulis, tetapi juga dibaca karena indeks Anda akan sangat terfragmentasi. dan kemungkinan mengandung jumlah ruang putih yang lebih tinggi (yang berarti penyimpanan dan memori yang terbuang).

Jika Anda merasa CustomerID harus menjadi kolom utama dari indeks berkerumun komposit, Anda dapat mengurangi dampak pemisahan halaman tengah dengan menyesuaikan FILLFACTORsemua indeks untuk tabel ini. Ini akan mengurangi jumlah pemisahan halaman tengah dengan meningkatkan ukuran tabel / indeks. Jika Anda ingin menggunakan rute ini, saya akan menyarankan pengujian dengan nilai 80 dan kurangi jika analisis mengungkapkan pemisahan halaman tengah masih mematikan kinerja.

Saran saya adalah menggunakan OrderId. OrderID secara alami harus berurutan dan menghasilkan lebih banyak pemisahan halaman akhir yang bagus dan diharapkan dengan pertumbuhan tabel. Selain itu pendekatan ini akan bermain lebih baik dengan Tabel Partisi jika Anda memilih untuk menggunakan kolom OrderDate sebagai kunci partisi. Mengenai kueri yang terus-menerus menggunakan bidang CustomerID, buat indeks nonclustered untuk menangani kueri tersebut. Indeks ini perlu didefinisikan dengan tepat FILLFACTORkarena akan menderita split halaman tengah yang saya sebutkan di atas, meskipun ini tidak akan seburuk keseluruhan berbeda dengan jika split terjadi terhadap indeks cluster.

Aktivitas pada DB kami sekitar 85% dibaca dan 15% ditulis.

CustomerID+ OrderID(dan menentukan fillfactor untuk memungkinkan pertumbuhan tanpa pemisahan) mungkin lebih baik jika penilaian itu berlaku. Hanya membuat yakin bahwa penilaian akurat. Tes tes tes.

John Eisbrener
sumber
1
Perhatikan bahwa memasukkan pesanan untuk Pelanggan terakhir (atau satu-satunya) pada halaman bukanlah "pemisahan halaman tengah". Jadi jika Pesanan per pelanggan tinggi, atau lebar baris besar, maka lebih sedikit sisipan Pesanan akan memerlukan "pemisahan halaman tengah".
David Browne - Microsoft