Kami menjalankan MySQL 5.1 pada Windows Server 2008 R2.
Kami telah melakukan beberapa diagnosa pada database kami akhir-akhir ini dan telah menemukan beberapa artefak mengganggu yang tidak dapat kami jelaskan . Kami menambahkan beberapa kode untuk dicatat ketika kami memiliki pertanyaan yang membutuhkan waktu lama (> 2000 ms). Hasilnya mengejutkan (dan mungkin penjelasan untuk kebuntuan kami).
Kadang-kadang pertanyaan, yang biasanya memakan waktu sangat sedikit (<10 ms), membutuhkan 4 hingga 13 detik. Agar jelas, ini adalah kueri yang berjalan terus-menerus (beberapa kali per detik) dan tidak menderita lonjakan waktu kueri ini.
Kami telah melalui indeks kami untuk mencari kesalahan yang jelas dan tidak memiliki banyak keberuntungan.
Memperbarui
Tabel orang:
| people | CREATE TABLE `people` (
`people_id` bigint(20) NOT NULL AUTO_INCREMENT,
`company_id` bigint(20) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`temp_password` varchar(10) DEFAULT NULL,
`reset_password_hash` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`phone` varchar(32) DEFAULT NULL,
`mobile` varchar(32) DEFAULT NULL,
`iphone_device_id` varchar(160) DEFAULT NULL,
`iphone_device_time` datetime DEFAULT NULL,
`last_checkin` datetime DEFAULT NULL,
`location_lat` double DEFAULT NULL,
`location_long` double DEFAULT NULL,
`gps_strength` smallint(6) DEFAULT NULL,
`picture_blob_id` bigint(20) DEFAULT NULL,
`authority` int(11) NOT NULL DEFAULT '0',
`active` tinyint(1) NOT NULL DEFAULT '1',
`date_created` datetime NOT NULL,
`last_login` datetime NOT NULL,
`panic_mode` tinyint(1) NOT NULL DEFAULT '0',
`battery_level` double DEFAULT NULL,
`battery_state` varchar(32) DEFAULT NULL,
PRIMARY KEY (`people_id`),
KEY `email` (`email`),
KEY `company_id` (`company_id`),
KEY `iphone_device_id` (`iphone_device_id`),
KEY `picture_blob_id` (`picture_blob_id`),
CONSTRAINT `people_ibfk_1` FOREIGN KEY (`company_id`) REFERENCES `companies` (`company_id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `people_ibfk_2` FOREIGN KEY (`picture_blob_id`) REFERENCES `blobs` (`blob_id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4658 DEFAULT CHARSET=utf8 |
Indeks:
+--------+------------+------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------+------------+------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+
| people | 0 | PRIMARY | 1 | people_id | A | 3502 | NULL | NULL | | BTREE | |
| people | 1 | email | 1 | email | A | 3502 | NULL | NULL | YES | BTREE | |
| people | 1 | company_id | 1 | company_id | A | 3502 | NULL | NULL | | BTREE | |
| people | 1 | iphone_device_id | 1 | iphone_device_id | A | 3502 | NULL | NULL | YES | BTREE | |
| people | 1 | picture_blob_id | 1 | picture_blob_id | A | 3502 | NULL | NULL | YES | BTREE | |
+--------+------------+------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+
kami memiliki ~ 5.000 baris dalam tabel di server yang memberi kami masalah.
sumber
Jawaban:
Kueri UPDATE dalam dua pertanyaan Anda sebelumnya ( Pertanyaan1 , Pertanyaan2 ) mengenai tabel 'orang' oleh PRIMARY KEY dengan penguncian level baris. Inilah yang saya nyatakan kembali di Pertanyaan1 pada 6 Juni 2011 10:03
Semua transaksi melintasi kunci UTAMA. Karena PRIMARY adalah indeks berkerumun di InnoDB, kunci PRIMARY dan baris itu sendiri bersama-sama. Dengan demikian, melintasi baris dan dan KUNCI UTAMA adalah satu dan sama. Oleh karena itu, setiap kunci indeks pada KUNCI UTAMA juga merupakan kunci tingkat baris.
Sesuatu yang lain belum dipertimbangkan yang dapat menghubungkan kelambatan ke indeks: Penggunaan indeks NON-UNIK di InnoDB. Setiap pencarian yang diindeks di InnoDB menggunakan indeks tidak unik juga memiliki rowID setiap baris yang dilampirkan pada kunci tidak unik. RowID pada dasarnya berasal dari Clustered Index . Memperbarui indeks non-unik HARUS SELALU berinteraksi dengan indeks berkerumun BAHKAN JIKA TABEL TIDAK PUNYA KUNCI UTAMA.
Hal lain yang perlu dipikirkan adalah proses mengelola node BTREE dalam indeks. Kadang-kadang, itu membutuhkan pemisahan halaman node. Semua entri dalam node BTREE indeks non-unik berisi bidang non-unik DITAMBAH rowID dalam indeks berkerumun. Untuk mengurangi pemisahan halaman BTREE tersebut tanpa mengganggu integritas data, baris yang terkait dengan rowID harus mengalami kunci tingkat baris secara internal.
Jika tabel 'people' memiliki banyak indeks non-unik, bersiaplah untuk memiliki sejumlah besar halaman indeks di tablespace serta memiliki kunci baris kecil kecil menyelinap pada Anda dari waktu ke waktu.
Ada faktor lain yang tidak begitu jelas: Populasi Kunci
Kadang-kadang ketika suatu indeks diisi, nilai-nilai kunci yang menyusun indeks dapat menjadi miring dari waktu ke waktu dan menyebabkan MySQL Query Optimizer untuk beralih dari pencarian kunci, untuk mengindeks scan, dan akhirnya ke scan tabel penuh. Bahwa Anda tidak dapat mengontrol kecuali Anda mendesain ulang tabel dengan indeks baru untuk mengimbangi kunci miring. Harap berikan struktur tabel untuk tabel 'orang', jumlah tabel 'orang', dan output indeks acara untuk tabel 'orang' .
Sekalipun kueri hanya menggunakan KUNCI UTAMA, ketidakseimbangan kunci dalam indeks non-unik masih membutuhkan penyeimbangan BTREE dan pemisahan halaman agar terjadi. Manajemen BTREE tersebut akan menghasilkan pelambatan penting karena penguncian level baris terputus-putus yang tidak Anda inginkan.
UPDATE 2011-06-14 22:19
Pertanyaan Dari Pertanyaan 1
Bayangkan urutan dalam peristiwa
Pertanyaan Dari Pertanyaan 2
Dua kueri ini bahkan lebih membingungkan karena kueri pertama memperbarui semuanya kecuali people_id 666. Ratusan baris dikunci dengan menyakitkan hanya dengan kueri pertama. Kueri kedua memperbarui people_id 666 menjalankan 5 urutan peristiwa. Kueri pertama menjalankan 5 urutan kejadian yang sama di setiap baris yang terlibat kecuali people_id 666 tetapi indeks untuk iphone_device_id berada di jalur interecept dengan dua kueri yang berbeda. Seseorang harus mengunci halaman BTREE dengan dasar siapa cepat dia dapat.
Menghadapi dua pasang kueri ini di jalur tabrakan untuk mungkin mengunci halaman BTREE yang sama dalam satu indeks bisa menjadi pengalaman yang menyayat hati untuk InnoDB atau RDBMS yang sesuai dengan ACID. Dengan demikian, pelambatan indeks adalah takdir dari pasangan kueri ini kecuali jika Anda dapat menjamin bahwa kueri dijalankan dengan AUTOCOMMIT = 1 atau dengan memungkinkan pembacaan kotor (meskipun tabrakan seperti ini membuat READ-COMMITTED dan READ-UNCOMMITED menjadi mimpi buruk untuk MVCC).
UPDATE 2011-06-15 10:29
@RedBlueThing: Dalam kueri dari pertanyaan 2, kueri pertama adalah kueri rentang, jadi banyak kunci baris diperoleh. Juga perhatikan kedua query mencoba untuk mengunci ruang id yang sama 0 halaman no 4611 n bit 152 sedang dikunci dalam KUNCI UTAMA, alias indeks berkerumun.
Untuk memastikan bahwa aplikasi Anda, paling tidak, berjalan berdasarkan rangkaian acara yang Anda harapkan, ada dua opsi yang bisa Anda coba:
Opsi 1) Konversi tabel ini ke MyISAM (setidaknya di server pengembangan). Setiap UPDATE, INSERT, dan DELETE akan memaksakan kunci tabel penuh atas dasar pertama datang, pertama dilayani.
Opsi 2) Coba gunakan tingkat isolasi SERIALIZABLE . Itu akan mengunci semua baris yang dimaksud dalam mode SHARED.
Urutan peristiwa yang Anda harapkan akan pecah atau berhasil menggunakan dua opsi alternatif ini. Jika kedua opsi ini gagal, maka Anda perlu memeriksa aplikasi Anda dan memprioritaskan urutan eksekusi permintaan Anda. Setelah Anda menetapkan prioritas itu, Anda dapat dengan mudah membatalkan opsi-opsi ini (Untuk opsi 1, kembali ke InnoDB, Untuk opsi 2, kembali ke tingkat isolasi default [berhenti menggunakan SERIALIZABLE]).
sumber
TAMPILKAN VARIABEL SEPERTI 'innodb%'; - Secara khusus, jika data dan indeks tidak mencapai ukuran buffer pool, Anda bisa memukul hard disk lebih keras dari sebelumnya. I / O adalah pembunuh kinerja besar.
Sebagian besar bidang Anda dua kali lebih besar dari yang dibutuhkan. BIGINT (8 byte) adalah cara yang berlebihan bagi sebagian besar id. 5000 baris hanya membutuhkan tanda SMALLINT UNSIGNED (batas 65K, hanya 2 byte). Atau gunakan MEDIUMINT untuk batas keamanan.
DOUBLE memberi Anda 16 digit signifikan dengan biaya 8 byte. Apakah battery_level memiliki presisi lebih dari 2 digit? FLOAT membutuhkan 4 byte.
Maksud saya di sini adalah bahwa "lebih kecil -> lebih mudah disimpan -> lebih cepat".
Tolong tunjukkan kepada kami pertanyaan lambat; setidaknya beberapa dari mereka yang tiba-tiba menjadi lebih lambat. Kita hanya bisa membuat tebakan tanpa itu. Nyalakan slowlog dan atur long_query_time = 1; ini akan membantu menemukan kueri paling lambat.
Apakah Anda memahami manfaat dari indeks "gabungan"?
sumber