8k kesalahan baris meluap saat memperbarui baris ukuran 5k

8

Saya mencoba untuk memperbarui tabel target yang memiliki satu baris ukuran 5k ke satu baris ukuran 5k juga.

Karena satu baris mudah untuk mengetahui ukuran aktual baris:

select *
from sys.dm_db_index_physical_stats(DB_ID('RODS_HSD_ES'), 
OBJECT_ID(N'TBL_BM_HSD_SUBJECT_AN_148_REPRO'), NULL, NULL, 'DETAILED')

Mereproduksi

Tabel tidak diubah sejak pembuatan. tidak melihat alasan mengapa itu harus gagal. Ide ide?

Yosi Dahari
sumber
2
Mirip dengan pertanyaan terakhir Anda . Kesalahan ini sementara membangun meja kerja untuk semacam juga i.stack.imgur.com/wenSE.png , i.stack.imgur.com/MVyXf.png
Martin Smith

Jawaban:

9

Masalahnya terkait dengan fakta Anda memperbarui kunci pengelompokan, dan tabel tujuan kebetulan memiliki skema partisi 1 . Ketika SQL Server diminta untuk memperbarui komponen kunci pengelompokan, itu harus melakukan UPDATEdan DELETE, atau pembaruan hibrid di mana beberapa baris diperbarui di tempat, dan beberapa tidak.

Jika Anda menghapus indeks berkerumun dari tabel tujuan, Anda akan melihat pembaruan berfungsi.

Pesan kesalahan, meskipun mungkin sedikit menyesatkan, akurat karena ukuran baris yang dihasilkan selama pembaruan melebihi panjang maksimum.

Saya sarankan Anda mempertimbangkan mengubah struktur tabel menjadi:

  • tidak digunakan VARCHAR(MAX)untuk semua kolom itu. Jika Anda sebenarnya tidak membutuhkan 2GB karakter dalam satu kolom, mengapa mendefinisikan kolom seperti itu? Tentukan kolom menjadi ukuran maksimum yang akan ditemui secara realistis.
  • mungkin membagi tabel ini menjadi beberapa tabel di mana ukuran baris maksimum yang dihasilkan kurang dari 8060 byte. Tampaknya Anda memiliki beberapa cluster logis dari kolom, seperti V_MAX_xxx, V_64_xxx, dan V_512_xxxkolom, dll

Untuk menyederhanakan repro Anda, Anda mungkin ingin menghilangkan kursor, dan hanya melakukan operasi DML berikut:

UPDATE dbo.TBL_BM_HSD_SUBJECT_AN_148_REPRO_TARGET
SET [sampletime]  = '2015-12-29 01:11:26.687';

Kolom di atas adalah salah satu komponen kunci clustering dan juga kunci partisi (memperbarui kolom kunci CI lainnya berfungsi dengan baik).

Dengan indeks berkerumun di tempat, Anda mendapatkan kesalahan ini:

Msg 511, Level 16, Status 1, Baris 1

Tidak dapat membuat baris ukuran 8287 yang lebih besar dari ukuran maksimum baris yang diijinkan 8060.

Pernyataan itu telah dihentikan.

Tanpa indeks berkerumun di tempat, pernyataan berhasil.


1 Menariknya, jika kita menghilangkan partisi dari repro, kita menemukan pembaruan berhasil, bahkan dengan indeks berkerumun di tempat.

Max Vernon
sumber
1
Saya pikir kita berada di jalan menuju solusi di sini. Pada dasarnya, sampletime adalah satu-satunya yang harus saya ubah, dan itu dalam indeks berkerumun hanya karena tabel dipartisi olehnya. Jadi solusinya adalah mengubah cara tabel dipartisi (yang menyakitkan, tetapi mungkin), dan kemudian indeks berkerumun
Yosi Dahari
10

Pembaruan gagal karena alasan yang hampir sama dengan yang saya jelaskan sebagai jawaban atas pertanyaan Anda sebelumnya .

Dalam hal ini, karena Anda berpotensi memperbarui beberapa baris di mana kolom kunci dari indeks yang unik adalah berubah * , SQL Server membangun rencana yang mencakup Split, Sort, dan operator Ciutkan untuk menghindari menengah pelanggaran kunci unik (lihat artikel ini untuk rincian) .

Operator Urut yang diperkenalkan kemudian menemukan baris perantara (termasuk overhead internal) dengan lebar yang melebihi batas, sehingga kesalahan muncul. Menambahkan OPTION (ROBUST PLAN)petunjuk ke permintaan pembaruan menunjukkan ini tidak dapat dihindari:

Msg 8619, Level 16, State 2, Line 681
Proses permintaan tidak dapat membuat rencana permintaan karena meja kerja diperlukan, dan ukuran baris minimumnya melebihi batas maksimum yang diijinkan 8060 byte. Alasan khas mengapa diperlukan meja kerja adalah klausa GROUP BY atau ORDER BY dalam kueri. Kirim ulang permintaan Anda tanpa petunjuk ROBUST PLAN.

Hubungan data sumber / target tidak jelas bagi saya dari pandangan singkat, tetapi jika Anda dapat menjamin bahwa setiap operasi pembaruan akan memengaruhi paling banyak satu baris, Anda dapat menghindari kebutuhan Split / Sortir / Perkecil dengan menambahkan TOP (1)pernyataan pembaruan:

UPDATE TOP (1) [TBL_BM_HSD_SUBJECT_AN_148_REPRO_TARGET] 
SET ...

Ini sedikit peretasan. Idealnya, konstruksi dan indeks pernyataan pembaruan harus memberikan informasi yang cukup kepada pengoptimal sehingga dapat melihat bahwa paling banyak satu baris akan diperbarui. Secara khusus, ini adalah praktik terbaik untuk menulis pernyataan pembaruan yang bersifat deterministik .

Mengingat desain yang aneh dan kurangnya kejelasan dalam pertanyaan, saya bahkan tidak mencoba untuk menguraikan hubungan data, atau perubahan permintaan & indeks yang akan diperlukan untuk mencapai ini secara detail.

* Sebagaimana Martin Smith tunjukkan dalam komentar, ini tidak akan menjadi masalah dalam situasi khusus ini jika tabel tidak dipartisi. Di mana pembaruan menetapkan kunci ke nilai deterministik yang sama di setiap baris, Split / Sortir / Perkecil tidak diperlukan, kecuali tabel juga dipartisi pada kunci itu. Jadi, solusi alternatif untuk kueri ini adalah tidak mempartisi tabel pada sampletime .

Paul White 9
sumber