Mysql: buat indeks pada 1,4 miliar catatan

9

Saya punya meja dengan 1,4 miliar catatan. Struktur tabel adalah sebagai berikut:

CREATE TABLE text_page (
    text VARCHAR(255),
    page_id INT UNSIGNED
) ENGINE=MYISAM DEFAULT CHARSET=ascii

Syaratnya adalah membuat indeks di atas kolom text.

Ukuran tabel sekitar 34G.

Saya telah mencoba membuat indeks dengan pernyataan berikut:

ALTER TABLE text_page ADD KEY ix_text (text)

Setelah 10 jam menunggu, akhirnya saya menyerah pada pendekatan ini.

Apakah ada solusi yang bisa diterapkan untuk masalah ini?

UPDATE : tabel tidak mungkin diperbarui atau dimasukkan atau dihapus. Alasan mengapa membuat indeks pada kolom textadalah karena jenis kueri sql ini akan sering dieksekusi:

SELECT page_id FROM text_page WHERE text = ?

UPDATE : Saya telah memecahkan masalah dengan mempartisi tabel.

Tabel dipartisi menjadi 40 bagian pada kolom text. Kemudian membuat indeks di atas meja membutuhkan waktu sekitar 1 jam untuk menyelesaikannya.

Tampaknya pembuatan indeks MySQL menjadi sangat lambat ketika ukuran tabel menjadi sangat besar. Dan partisi mengurangi tabel menjadi batang yang lebih kecil.

SiNent SoNG
sumber
1
Apa yang salah dengan menggunakan CREATE INDEXpernyataan normal ?
Saya menyarankan pertanyaan ini mungkin lebih baik di ServerFault - ini lebih merupakan admin DB daripada pertanyaan pemrograman.
dari sana
@Derk: pendekatan CREATE INDEX normal terlalu lambat. Saya harus menyelesaikan tugas dalam 1 hari.
1
Hmm ... Saya tidak berpikir Anda bisa menyelesaikan ini. Membangun indeks membutuhkan DBMS untuk memindai semua catatan, mengumpulkan bidang "teks" mereka dan menyisipkan / mengubah simpul pohon / sub pohon yang sesuai. Dan ini membutuhkan banyak waktu untuk 34G ...
chiccodoro
Berapa banyak memori yang dimiliki server DB Anda? Sudahkah Anda mengkonfigurasi MySQL untuk menggunakan semua memori itu, atau apakah itu membatasi dirinya?

Jawaban:

4

Mungkinkah sistem Anda tidak sesuai dengan tugas? Saya tidak menggunakan MySQL (SQL Server di sini), tapi saya tahu sakitnya mengindeks tabel entri 800 juta. Pada dasarnya .... Anda memerlukan perangkat keras yang tepat untuk itu (seperti pada: banyak cakram cepat). Saya sekarang menggunakan hampir selusin Velociraptors dan kinerjanya bagus;)

SQL Server (bukan sebagai MS SQL Server, tetapi sebagai server basis data yang menggunakan SQL) hidup dan mati dengan akses disk, dan disk normal tidak cukup untuk tugas operasi yang lebih besar.

TomTom
sumber
Keraguan saya adalah bahwa pembuatan indeks biasanya sangat cepat jika jumlah catatan kecil; katakan jutaan. Tetapi ketika hitungannya mencapai miliaran, pembuatan indeks menjadi sangat lambat. Sepertinya pertumbuhan waktu itu eksponensial.
Seharusnya tidak begitu. MySQL secara umum memiliki batasan, tetapi itu bukan database omong kosong, dan itu akan SANGAT buruk. Pembuatan indeks menjadi lebih lambat, tetapi dengan log (n), bukan (n), jadi seharusnya tidak terlalu buruk.
TomTom
4

Anda mungkin ingin membuat indeks pada karakter pertama (misalnya, 10) dari bidang teks.

Dari Documents:

Indeks dapat dibuat yang hanya menggunakan bagian terdepan dari nilai kolom, menggunakan sintaks col_name (panjang) untuk menentukan panjang awalan indeks:

CREATE INDEX ix_text ON text_page (text(10))

sumber
4

Saya telah memecahkan masalah dengan mempartisi tabel.

Tabel dipartisi menjadi 40 bagian pada kolom text. Kemudian membuat indeks di atas meja membutuhkan waktu sekitar 1 jam untuk menyelesaikannya.

Tampaknya pembuatan indeks MySQL menjadi sangat lambat ketika ukuran tabel menjadi sangat besar. Dan partisi mengurangi tabel menjadi batang yang lebih kecil.

SiNent SoNG
sumber
Jadi 40 x 1 jam kurang dari 10 jam?
symcbean
3

Atur sort_buffer_size ke 4GB (atau seberapa banyak Anda dapat bergantung pada berapa banyak memori yang Anda miliki).

Saat ini indeks buat sedang melakukan semacam tetapi karena Anda memiliki sort_buffer_size 32MB, itu pada dasarnya meronta-ronta hard drive tidak perlu.

mengadu
sumber
Posting-posting ini secara langsung sangat tidak setuju dengan Anda: xaprb.com/blog/2010/05/09/how-to-tune-mysqls-sort_buffer_size dan lebih baik ronaldbradford.com/blog/... Sepertinya itu bukan nilai global, itu per-kueri, jadi itu 4GB per kueri yang Anda rekomendasikan. Selain itu, ketika melebihi 256 ribu, memori dip-mapped ke disk daripada memori yang sebenarnya dalam memori. Jika Anda tetap kecil itu membutuhkan beberapa lintasan, tetapi ia menghindari disk (tidak bertukar).
Ry4an Brase
3

Jika Anda tidak perlu membuat kueri seperti:

SELECT page_id FROM text_page WHERE text LIKE '?%';

Saya akan menyarankan membuat kolom hash baru dan indeks tabel dengan kolom. Ukuran keseluruhan tabel + indeks mungkin jauh lebih kecil.

UPD : Omong-omong, 1,4 miliar integer kunci primer menempati sekitar 6 GB, yaitu panjang rata-rata string kurang dari 30 karakter, yang mengindeks pada awalan mungkin lebih disukai.

Anda juga harus melihat mesin penyimpanan MERGE .

baru ditemukan
sumber
2

Salah satu cara untuk melakukan ini adalah membuat tabel baru dengan set indeks dan menyalin data ke tabel baru.

Juga, pastikan Anda memiliki ruang temp yang cukup.

didekompilasi
sumber
1
Saya sudah mencoba pendekatan ini. Setelah 10 jam, kurang dari 1% data telah disalin ke tabel baru.
1
Bung ... ini 1,4 MILIAR catatan. Bukan jutaan, MILIAR. Itu banyak. Bagaimanapun juga itu akan memakan waktu.
Jika Anda memilih untuk melakukan metode ini, pisahkan salinan menjadi potongan-potongan kecil. Katakan sekitar 100 hingga 200 juta untuk setiap salinan.
1
@ didekompilasi, memecahnya menjadi potongan-potongan kecil tidak akan melakukan apa-apa (sebenarnya, itu mungkin membuatnya kurang efisien). @Bryan, Bahkan dengan 1,4 miliar catatan, seharusnya tidak perlu 1.000 jam.
0

Jika Anda masih bertanya-tanya bagaimana melakukan yang terbaik ini, saya akan menyarankan Anda untuk menggunakan alat tabel alter online.

Ada banyak dari mereka di internet, salah satu yang terkenal adalah:

Kami memiliki masalah yang sama dengan tabel besar (lebih dari 500 mil catatan) dan perubahannya berjalan dengan sempurna. Ini menciptakan tabel tmp baru, menambahkan pemicu pada tabel asli (untuk pembaruan baru / menghapus / menyisipkan catatan) dan sementara itu menyalin semua catatan ke tabel baru (dengan struktur baru)

Semoga berhasil!

Ali Alwash
sumber