Ubah batas untuk "Ukuran Baris Mysql terlalu besar"

104

Bagaimana saya bisa mengubah batas

Ukuran baris terlalu besar (> 8126). Mengubah beberapa kolom menjadi TEXT atau BLOB atau menggunakan ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSEDmungkin membantu. Dalam format baris saat ini, BLOBprefiks 768 byte disimpan sebaris.

Meja:

id  int(11) No       
name    text    No       
date    date    No       
time    time    No       
schedule    int(11) No       
category    int(11) No       
top_a   varchar(255)    No       
top_b   varchar(255)    No       
top_c   varchar(255)    No       
top_d   varchar(255)    No       
top_e   varchar(255)    No       
top_f   varchar(255)    No       
top_g   varchar(255)    No       
top_h   varchar(255)    No       
top_i   varchar(255)    No       
top_j   varchar(255)    No       
top_title_a varchar(255)    No       
top_title_b varchar(255)    No       
top_title_c varchar(255)    No       
top_title_d varchar(255)    No       
top_title_e varchar(255)    No       
top_title_f varchar(255)    No       
top_title_g varchar(255)    No       
top_title_h varchar(255)    No       
top_title_i varchar(255)    No       
top_title_j varchar(255)    No       
top_desc_a  text    No       
top_desc_b  text    No       
top_desc_c  text    No       
top_desc_d  text    No       
top_desc_e  text    No       
top_desc_f  text    No       
top_desc_g  text    No       
top_desc_h  text    No       
top_desc_i  text    No       
top_desc_j  text    No       
status  int(11) No       
admin_id    int(11) No 
Lasha Kurt
sumber
1
Apa yang Nosedang ditampilkan?
hjpotter92
Tidak dapat memperbarui kesalahan "Ukuran baris terlalu besar (> 8126). Mengubah beberapa kolom menjadi TEXT atau BLOB atau menggunakan ROW_FORMAT = DYNAMIC atau ROW_FORMAT = COMPRESSED mungkin membantu. Dalam format baris saat ini, awalan BLOB dari 768 byte disimpan sebaris."
Lasha Kurt
Dapatkah Anda menambahkan beberapa detail lain ke posting Anda, setidaknya sebagai komentar?
Eineki
1
Jika data ini ada di tabel lain, pertimbangkan untuk menggunakan kunci asing sebagai gantinya, ini akan secara dramatis mengurangi ukuran baris Anda, dan menormalkan skema database Anda.
didierc
1
@AL: Ups, Anda benar
berikan

Jawaban:

121

Pertanyaan telah ditanyakan pada serverfault juga.

Anda mungkin ingin melihat artikel ini yang menjelaskan banyak tentang ukuran baris MySQL. Penting untuk diperhatikan bahwa meskipun Anda menggunakan bidang TEXT atau BLOB, ukuran baris Anda masih bisa lebih dari 8K (batas untuk InnoDB) karena menyimpan 768 byte pertama untuk setiap bidang sebaris di halaman.

Cara termudah untuk memperbaikinya adalah dengan menggunakan format file Barracuda dengan InnoDB. Ini pada dasarnya menghilangkan masalah sama sekali dengan hanya menyimpan penunjuk 20 byte ke data teks daripada menyimpan 768 byte pertama.


Metode yang berhasil untuk OP itu adalah:

  1. Tambahkan berikut ini ke my.cnffile di bawah [mysqld]bagian.

    innodb_file_per_table=1
    innodb_file_format = Barracuda
    
  2. ALTERtabel untuk digunakan ROW_FORMAT=COMPRESSED.

    ALTER TABLE nombre_tabla
        ENGINE=InnoDB
        ROW_FORMAT=COMPRESSED 
        KEY_BLOCK_SIZE=8;
    

Ada kemungkinan hal di atas masih belum menyelesaikan masalah Anda. Ini adalah bug yang diketahui (dan diverifikasi) dengan mesin InnoDB , dan perbaikan sementara untuk saat ini adalah kembali ke mesin MyISAM sebagai penyimpanan sementara. Jadi, di my.cnffile Anda :

internal_tmp_disk_storage_engine=MyISAM
hjpotter92
sumber
12
+1 -> Bagian innodb_file_per_table sangat penting dan sejalan dengan mengubah format ke Barracuda. Tanpanya, MySQL akan terus menggunakan Antelope secara diam-diam.
Nick
1
@Eduardo Saya akan merekomendasikan untuk mencadangkan data terlebih dahulu. Tapi ya, Anda juga bisa melakukan ini pada produksi!
hjpotter92
3
Gunakan innodb_file_per_table=1untuk mengaktifkan opsi ini.
Stijn Geukens
2
Ini tidak dijamin dapat memperbaiki masalah. Lihat posting ini untuk contoh skrip yang menambahkan pengaturan ini tetapi masih dapat mereproduksi kesalahan.
Cerin
1
@ user1183352 Memperbarui balasan saya di atas. Terima kasih telah mengingatkan saya lagi untuk menyelami hal ini lebih dalam. :)
hjpotter92
61

Saya mengalami masalah ini baru-baru ini dan menyelesaikannya dengan cara yang berbeda. Jika Anda menjalankan MySQL versi 5.6.20, ada bug yang diketahui di sistem. Lihat dokumen MySQL

Penting Karena Bug # 69477, mengulang penulisan log untuk bidang BLOB yang besar dan disimpan secara eksternal dapat menimpa checkpoint terbaru. Untuk mengatasi bug ini, patch yang diperkenalkan di MySQL 5.6.20 membatasi ukuran redo log BLOB write hingga 10% dari ukuran file redo log. Sebagai hasil dari batas ini, innodb_log_file_size harus disetel ke nilai yang lebih besar dari 10 kali ukuran data BLOB terbesar yang ditemukan di baris tabel Anda ditambah panjang bidang panjang variabel lainnya (bidang jenis VARCHAR, VARBINARY, dan TEXT).

Dalam situasi saya, tabel blob yang menyinggung berukuran sekitar 16MB. Jadi, cara saya menyelesaikannya adalah dengan menambahkan baris ke my.cnf yang memastikan saya memiliki setidaknya 10x jumlah itu dan kemudian beberapa:

innodb_log_file_size = 256M

Colin
sumber
Tepat. Kesalahan "Ukuran Baris terlalu besar" saya di longblobbidang menghilang segera setelah saya meningkatkan innodb_log_file_sizeparameter. Juga menjalankan 5.6.20.
adamup
Terima kasih. Menjalankan homebrew 5.6.21, mengubah parameter memperbaiki masalah.
nanoman
Baik ini dan jawaban @ hjpotter92 diperlukan untuk memperbaiki kesalahan ini untuk saya.
Cerin
Terima kasih. Menjalankan 5.6.21 dan solusi ini membantu.
petiar
Ini juga tidak menyelesaikan masalah saya. Saya sedang mempertimbangkan untuk mengganti banyak bidang VARCHAR saya ke TEXT, seperti yang pernah saya lihat di utas serupa.
PDoria
28

Tetapkan yang berikut pada file my.cnf Anda dan mulai ulang server mysql.

innodb_strict_mode=0
Karl
sumber
2
innodb_strict_mode=0-> tanpa spasi. Jika tidak, memulai ulang mariaDB 10.2 menghasilkan kesalahan :-P
Pathros
Saya tidak mencoba dengan mariadb, untuk MySQL tidak perlu menghapus spasi.
Karl
1
Sesuai dengan dokumentasi, menonaktifkan mode ketat hanya mencegah kesalahan dan peringatan muncul, jadi sepertinya tidak menyelesaikan masalah! download.nust.na/pub6/mysql/doc/innodb-plugin/1.1/en/…
João Teixeira
2
Ini sepertinya berhasil dan biarkan saya membuat tabel tanpa masalah dan menyimpan data
Chris Muench
@ João, itu lebih .. dev.mysql.com/doc/refman/8.0/en/…
Karl
24

Jika Anda dapat mengganti ENGINE dan menggunakan MyISAM daripada InnoDB, itu akan membantu:

ENGINE=MyISAM

Ada dua peringatan dengan MyISAM (bisa dibilang lebih):

  1. Anda tidak dapat menggunakan transaksi.
  2. Anda tidak dapat menggunakan batasan kunci asing.
burung phoenix
sumber
5
Baik jika Anda tidak keberatan pergi tanpa transaksi dan kendala kunci asing. Tetapi ketahuilah bahwa Anda kehilangan ini saat beralih ke MyISAM.
wobbily_col
Nasihat ini tidak masuk akal - setidaknya frase itu akan selalu menjadi peringatan! Transaksi dan kendala utama sebelumnya adalah masalah terkecil dengan format ini!
Hassan Syed
Maaf tidak menyukai jawaban ini. Harap perbarui untuk menyebutkan semua peringatan yang terlibat. Siapa pun yang mengikuti saran ini akan beralih ke format yang tidak akan pernah saya gunakan pada sistem produksi apa pun.
Remco Wendt
2
Dan MyISAM akan dihentikan.
Rick James
2
bekerja untuk saya. Kasus saya, saya memiliki lebih dari 300 bidang dengan panjang masing-masing sekitar 10. Saya tidak memiliki hubungan apa pun dalam tabel ini sehingga beralih ke MyISAM adalah solusinya.
Robert Saylor
12

Saya ingin membagikan jawaban yang luar biasa, mungkin bisa membantu. Kredit Tagihan Karwin lihat di sini /dba/6598/innodb-create-table-error-row-size-too-large

Mereka bervariasi berdasarkan format file InnoDB. Saat ini ada 2 format yang disebut Antelope dan Barracuda.

File tablespace pusat (ibdata1) selalu dalam format Antelope. Jika Anda menggunakan file-per-table, Anda dapat membuat file individual menggunakan format Barracuda dengan mengatur innodb_file_format = Barracuda di my.cnf.

Poin dasar:

  1. Satu halaman 16 KB data InnoDB harus menampung setidaknya dua baris data. Ditambah setiap halaman memiliki header dan footer yang berisi checksum halaman dan nomor urut log dan sebagainya. Di situlah Anda mendapatkan batas Anda sedikit kurang dari 8KB per baris.

  2. Tipe data ukuran tetap seperti INTEGER, DATE, FLOAT, CHAR disimpan di halaman data utama ini dan dihitung dalam batas ukuran baris.

  3. Jenis data berukuran variabel seperti VARCHAR, TEXT, BLOB disimpan di halaman tambahan, sehingga tidak dihitung sepenuhnya terhadap batas ukuran baris. Di Antelope, hingga 768 byte dari kolom tersebut disimpan di halaman data utama selain disimpan di halaman overflow. Barracuda mendukung format baris dinamis, sehingga hanya dapat menyimpan penunjuk 20-byte pada halaman data utama.

  4. Tipe data ukuran variabel juga diawali dengan 1 atau lebih byte untuk menyandikan panjangnya. Dan format baris InnoDB juga memiliki array ofset lapangan. Jadi ada struktur internal yang kurang lebih didokumentasikan di wiki mereka.

Barracuda juga mendukung ROW_FORMAT = COMPRESSED untuk mendapatkan efisiensi penyimpanan lebih lanjut untuk data overflow.

Saya juga harus berkomentar bahwa saya belum pernah melihat tabel yang dirancang dengan baik melebihi batas ukuran baris. Ini adalah "bau kode" yang kuat bahwa Anda melanggar ketentuan grup berulang dari Formulir Normal Pertama.

Aman Chhabra
sumber
7

Saya memiliki masalah yang sama, ini menyelesaikannya untuk saya:

ALTER TABLE `my_table` ROW_FORMAT=DYNAMIC;

Dari Dokumentasi MYSQL :

Format baris DINAMIS mempertahankan efisiensi penyimpanan seluruh baris dalam node indeks jika cocok (seperti halnya format COMPACT dan REDUNDANT), tetapi format baru ini menghindari masalah pengisian node B-tree dengan sejumlah besar byte data kolom panjang. Format DINAMIS didasarkan pada gagasan bahwa jika sebagian dari nilai data yang panjang disimpan di luar halaman, biasanya paling efisien untuk menyimpan semua nilai di luar halaman. Dengan format DINAMIS, kolom yang lebih pendek cenderung tetap berada di simpul pohon-B, meminimalkan jumlah halaman tambahan yang diperlukan untuk baris tertentu.

multimediaxp
sumber
... tetapi Anda harus memiliki format file yang berbeda, jadi Anda sudah menggunakan Barracuda? Karena saya mendapatkan kesalahan saat mencoba perintah itu, mengatakanWarnings from last query: InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope
Ted
Ketika saya membiarkan HeidiSQL menjalankan perintah yang sama melalui GUI bawaannya, entah bagaimana berhasil, tetapi tidak membantu sama sekali, saya mendapatkan kesalahan yang sama,Row size too large (>8126)
Ted
Cobalah untuk mengatur innodb_file_format = Barracuda di my.ini dan coba ALTER TABLE my_tableROW_FORMAT = DYNAMIC; lagi
multimediaxp
Ya, saya pikir itulah yang pada akhirnya saya lakukan, dan saya pikir itu menyelesaikannya. Tetapi saya juga mengubah banyak kolom menjadi TEXT pada saat yang sama dengan putus asa =) Terima kasih, saya benar-benar berpikir hanya itu.
Ted
Bagus !, jika menurut Anda ini adalah jawaban yang bagus, berikan suara dan terima sebagai tanggapan yang valid, terima kasih!
multimediaxp
5

Setelah menghabiskan berjam-jam saya telah menemukan solusinya: jalankan saja SQL berikut di admin MySQL Anda untuk mengonversi tabel ke MyISAM:

USE db_name;
ALTER TABLE table_name ENGINE=MYISAM;
Iftikhar Khan
sumber
Tidak banyak membantu jika masalah terjadi dalam pernyataan buat tabel.
Mark Fraser
create tablememiliki opsi yang sama:CREATE TABLE ... ENGINE=MyISAM ...
xebeche
3

Saya mengalami masalah ini ketika saya mencoba memulihkan database mysql yang dicadangkan dari server yang berbeda. Apa yang memecahkan masalah ini bagi saya adalah menambahkan pengaturan tertentu ke my.conf (seperti dalam pertanyaan di atas) dan juga mengubah file cadangan sql:

Langkah 1: Tambahkan atau edit baris berikut di my.conf:

innodb_page_size=32K
innodb_file_format=Barracuda
innodb_file_per_table=1

Langkah 2 tambahkan ROW_FORMAT = DYNAMIC ke tabel buat pernyataan di file cadangan sql untuk tabel yang menyebabkan kesalahan ini:

DROP TABLE IF EXISTS `problematic_table`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `problematic_table` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
  ...
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 ROW_FORMAT=DYNAMIC;

perubahan penting di atas adalah ROW_FORMAT = DYNAMIC; (yang tidak termasuk dalam file cadangan orignal sql)

sumber yang membantu saya menyelesaikan masalah ini: MariaDB dan InnoDB Ukuran Baris MySQL terlalu besar

matyas
sumber
1
Baris yang dijelaskan pada langkah 1 tidak boleh memiliki spasi. Jalur innodb_page_size=32Ktidak berfungsi, karena menyebabkan kesalahan untuk memulai ulang MariaDB 10.2 dalam kasus saya. Sebagai gantinya, saya menambahkan innodb_strict_mode=0baris, seperti yang dijelaskan di sini
Pathros
1
terima kasih atas umpan balik Pathros, saya memperbarui jawaban saya dan menghapus spasi dari langkah1.
matyas
Catatan untuk MySQL <= 5.7.5: 32K bukanlah opsi yang valid untuk innodb_page_size. Lihat: dev.mysql.com/doc/refman/5.6/en/…
Dub Nazar
Juga, Anda harus membuat ulang seluruh server mysql Anda untuk scracth, karena perubahan innodb_page_sizemembutuhkan ibdata*rekreasi, yang merupakan operasi yang merusak. Perhatikan syslog Anda untuk informasi lebih lanjut
Matija Nalis
2

Jawaban lainnya menjawab pertanyaan yang diajukan. Saya akan membahas penyebab yang mendasarinya: desain skema yang buruk.

Jangan melebarkan array di seluruh kolom. Di sini Anda memiliki 3 * 10 kolom yang harus diubah menjadi 10 baris dari 3 kolom dalam tabel baru (plus id, dll)

MainMeja Anda hanya akan memiliki

id  int(11) No       
name    text    No       
date    date    No       
time    time    No       
schedule    int(11) No       
category    int(11) No       
status  int(11) No       
admin_id    int(11) No 

Tabel ekstra Anda ( Top) akan memiliki

id  int(11) No          -- for joining to Main
seq TINYINT UNSIGNED    -- containing 1..10
img   varchar(255)    No       
title varchar(255)    No       
desc  text    No    
PRIMARY KEY(id, seq)    -- so you can easily find the 10 top_titles

Akan ada 10 baris (atau lebih sedikit? Atau lebih?) Di Topsetiap baris id.

Ini menghilangkan masalah asli Anda, dan membersihkan skema. (Ini bukan "normalisasi", seperti yang diperdebatkan di beberapa Komentar.)

Apakah tidak beralih ke MyISAM; itu akan pergi.
Jangan khawatir ROW_FORMAT.

Anda perlu mengubah kode untuk melakukan JOINdan menangani beberapa baris, bukan beberapa kolom.

Rick James
sumber
1

Saya menggunakan MySQL 5.6 di AWS RDS. Saya memperbarui mengikuti di grup parameter.

innodb_file_per_table=1
innodb_file_format = Barracuda

Saya harus mem-boot ulang instans DB agar perubahan grup parameter berlaku.

Selain itu, ROW_FORMAT = COMPRESSED tidak didukung. Saya menggunakan DINAMIS seperti di bawah ini dan berfungsi dengan baik.

ALTER TABLE nombre_tabla ENGINE=InnoDB ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=8
Mihir Kagrana
sumber
1

Ukuran baris maksimum untuk tabel InnoDB, yang berlaku untuk data yang disimpan secara lokal dalam halaman database, sedikit kurang dari setengah halaman untuk 4KB, 8KB, 16KB, dan 32KB

Untuk halaman 16kb (default), kami dapat menghitung:

Slightly less than half a page 8126 / Number of bytes to threshold for overflow 767 = 10.59 fields of 767 bytes maximum

Pada dasarnya, Anda dapat memaksimalkan baris dengan:

  • 11 bidang varchar> 767 karakter (latin1 = 1 byte per karakter) atau
  • 11 bidang varchar> 255 karakter (utf-8 di mysql = 3 byte per karakter).

Ingat, ini hanya akan meluap ke halaman overflow jika bidang> 767 byte. Jika ada terlalu banyak bidang 767 byte, itu akan rusak (melewati ukuran_kurang maksimum). Tidak biasa dengan latin1 tetapi sangat mungkin dengan utf-8 jika pengembang tidak berhati-hati.

Untuk kasus ini, saya pikir Anda mungkin bisa meningkatkan innodb_page_size menjadi 32kb.

di my.cnf:

innodb_page_size=32K

Referensi:

U0001
sumber
0

Saya juga mengalami masalah yang sama. Saya menyelesaikan masalah dengan menjalankan sql berikut:

ALTER ${table} ROW_FORMAT=COMPRESSED;

Tapi, saya pikir Anda harus tahu tentang Row Storage .
Ada dua jenis kolom: kolom dengan panjang variabel (seperti jenis VARCHAR, VARBINARY, dan BLOB dan TEXT) dan kolom dengan panjang tetap . Mereka disimpan di berbagai jenis halaman.

Kolom dengan panjang variabel adalah pengecualian untuk aturan ini. Kolom seperti BLOB dan VARCHAR yang terlalu panjang untuk dimuat pada halaman B-tree disimpan pada halaman disk yang dialokasikan secara terpisah yang disebut halaman overflow. Kami menyebut kolom seperti itu kolom di luar halaman. Nilai dari kolom ini disimpan dalam daftar halaman luapan tertaut tunggal, dan setiap kolom tersebut memiliki daftar satu atau beberapa halaman luapan sendiri. Dalam beberapa kasus, semua atau awalan dari nilai kolom panjang disimpan di pohon-B, untuk menghindari pemborosan penyimpanan dan menghilangkan kebutuhan untuk membaca halaman terpisah.

dan saat tujuan menyetel ROW_FORMAT adalah

Ketika tabel dibuat dengan ROW_FORMAT = DYNAMIC atau ROW_FORMAT = COMPRESSED, InnoDB dapat menyimpan nilai kolom panjang variabel (untuk jenis VARCHAR, VARBINARY, dan BLOB dan TEXT) sepenuhnya di luar halaman, dengan catatan indeks berkerumun hanya berisi 20- penunjuk byte ke halaman luapan.

Ingin tahu lebih banyak tentang DINAMIS dan Format Baris Terkompresi

Akan
sumber
0

Jika ini terjadi pada SELECT dengan banyak kolom, penyebabnya bisa jadi mysql membuat tabel sementara. Jika tabel ini terlalu besar untuk dimasukkan ke dalam memori, ia akan menggunakan format tabel temp default, yaitu InnoDB, untuk menyimpannya di Disk. Dalam kasus ini, batas ukuran InnoDB berlaku.

Anda kemudian memiliki 4 opsi:

  1. mengubah batas ukuran baris innodb seperti yang dinyatakan di posting lain, yang memerlukan inisialisasi ulang server.
  2. ubah kueri Anda untuk menyertakan lebih sedikit kolom atau hindari membuatnya membuat tabel sementara (misalnya, menghapus urutan berdasarkan dan klausa batas).
  3. mengubah max_heap_table_size menjadi besar sehingga hasilnya cocok dengan memori dan tidak perlu ditulis ke disk.
  4. ubah format tabel temp default menjadi MYISAM, inilah yang saya lakukan. Ubah my.cnf:

    internal_tmp_disk_storage_engine=MYISAM

Mulai ulang mysql, kueri berfungsi.

bhelm
sumber
0

Berikut tip sederhana untuk siapa pun yang tertarik:

Setelah memutakhirkan dari Debian 9 ke Debian 10 dengan 10.3.17-MariaDB, saya mengalami beberapa kesalahan dari database Joomla:

[Peringatan] InnoDB: Tidak dapat menambahkan bidang fielddi tabel database. tablekarena setelah ditambahkan ukuran baris adalah 8742 yang lebih besar dari ukuran maksimum yang diperbolehkan (8126) untuk dicatat pada halaman daun indeks.

Untuk berjaga-jaga, saya menetapkan innodb_default_row_format = DYNAMIC di /etc/mysql/mariadb.conf.d/50-server.cnf (toh defaultnya)

Kemudian, saya telah menggunakan phpmyadmin untuk menjalankan "Optimalkan tabel" untuk semua tabel di database Joomla. Saya pikir rekreasi meja yang dilakukan oleh phpmyadmin dalam prosesnya membantu. Jika Anda kebetulan menginstal phpmyadmin, cukup dengan beberapa klik saja.

joomlauser
sumber
Jika Anda adalah pengguna Joomla, bergabunglah dengan kami di Joomla Stack Exchange - kami selalu dapat menggunakan kontributor baru.
mickmackusa