Virtualizer Data »Apakah beberapa peristiwa MySQL yang tertunda benar-benar waktu CPU?

Database


Tentu saja, waktu tunggu acara di database mana pun mencakup beberapa waktu CPU, meskipun idealnya harus minimal. Menunggu harus sedekat mungkin dengan acara menunggu CPU, misalnya, jika saya melakukan IO, saya ingin menunggu hanya mencakup panggilan baca:


start_wait('my_read_wait');
pread( ... );
end_wait('my_read_wait');

Jadi fungsi saya, yang menyesuaikan pembacaan, melakukan beberapa CPU yang mungkin menunggu di bawah penutupnya, dan panggilan untuk pread menggunakan beberapa CPU, tetapi sebagian besar waktu saya harus menunggu I / O yang sebenarnya jika I / O Itu datang dari Anbar.

start_wait('my_lock');
semtimedop(...);
end_wait('my_lock');

Di MySQL saya telah menemukan bahwa jumlah rata-rata sesi CPU aktif seringkali jauh lebih rendah daripada yang dilaporkan oleh host sebagai penggunaan CPU. Misalnya, jika saya memiliki koneksi ke CPU, 100% dari waktu pada host 2 vCPU, penggunaan CPU harus sekitar 50%. Mungkin ada beberapa aktivitas CPU lain oleh proses lain, tetapi jika database hanya sesuatu di host dan saya hanya memiliki satu koneksi aktif, ini adalah perkiraan yang sangat baik. Sambungan di CPU adalah 100% dari waktu sesi aktif rata-rata (AAS) di CPU atau 1 AAS di CPU.

Pada sistem MySQL, saya sering melihat AAS pada CPU rata-rata 10%, sedangkan penggunaan CPU dari host 50% atau bahkan 100%.

Akhirnya hari ini saya melakukan tes di mana saya memiliki 2 sesi pada host 2 vCPU menggunakan tabel 3 kali dan tanpa indeks dan tanpa filter predikat, saya menjalankan Gabung. Ini pada dasarnya menyebabkan SQL melakukan pencarian N * N * N di mana N adalah jumlah baris dalam tabel. Dalam hal ini, tabel ada di memori, jadi itu pasti operasi CPU murni, dan ya, sistem operasi host telah melaporkan CPU 100%. Tapi itu rendah dan lihat tentang saya NOL AAS pada CPU dan 2 AAS menunggu ‘tunggu / io / tabel / sql / handler ‘keluar.

Di MySQL saya selalu melihat “tunggu / io / tabel / sql / handler” dengan harapan tinggi, dan itu terjadi ketika menjalankan SQL harus membaca buffer memori saja. Misalnya:


CREATE TABLE seed ( id INT AUTO_INCREMENT PRIMARY KEY, val INT);
 insert into seed(val) values (1);
 insert into seed(val) select val from seed; /* 2 */
 insert into seed(val) select val from seed; /* 4 */
 insert into seed(val) select val from seed; /* 8 */
 insert into seed(val) select val from seed; /* 16 */
 insert into seed(val) select val from seed; /* 32 */
 insert into seed(val) select val from seed; /* 64 */
 insert into seed(val) select val from seed; /* 128 */
 insert into seed(val) select val from seed; /* 256 */
 insert into seed(val) select val from seed; /* 512 */
 insert into seed(val) select val from seed; /* 1024 */
 insert into seed(val) select val from seed; /* 2048 */
 insert into seed(val) select val from seed; /* 4096 */
 insert into seed(val) select val from seed; /* 8192 */
 insert into seed(val) select val from seed; /* 16384 */
create table seed1 as select * from seed;
create table seed2 as select * from seed;

Kemudian jalankan kueri berikut untuk beberapa sesi.


select count(*) from seed a, seed1 b, seed2 c where a.id=b.id and a.id=c.id;

Berikut adalah dasbor Performance Insights di Amazon RDS. Memanfaatkan CPU pergi dari sekitar 5% sampai 100% dan DB Load dari 0 sampai 2 dengan beban hampir penuh pada “tunggu / io / tabel / sql / handler”.

Tangkapan layar 05/11/2021 pukul 11.01.59 malam

Sekarang jika kita menunggu IO. Kita dapat melihat bahwa pengambilan dibungkus di sekitar baris, tanpa melihat apakah pengambilan melakukan I / O atau membaca dari cache:

https://github.com/mysql/mysql-server/blob/5.7/sql/handler.cc#L3047

 MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result,
 { result= index_read_map(buf, key, keypart_map, find_flag); })
 if (!result && m_update_generated_read_fields)
 {
 result= update_generated_read_fields(buf, table, active_index);
 m_update_generated_read_fields= false;
 }
 DBUG_RETURN(result);
}
index_read_map:  https://github.com/mysql/mysql-server/blob/5.7/sql/handler.h#L2819
  virtual int index_read_map(uchar * buf, const uchar * key,
                             key_part_map keypart_map,
                             enum ha_rkey_function find_flag)
  {
    uint key_len= calculate_key_len(table, active_index, keypart_map);
    return  index_read(buf, key, key_len, find_flag);
  }
calculate_key_len:  https://github.com/mysql/mysql-server/blob/5.7/sql/handler.cc#L3047
uint calculate_key_len(TABLE *table, uint key,
                       key_part_map keypart_map)
{
  /* works only with key prefixes */
  assert(((keypart_map + 1) & keypart_map) == 0);

  KEY *key_info= table->key_info + key;
  KEY_PART_INFO *key_part= key_info->key_part;
  KEY_PART_INFO *end_key_part= key_part + actual_key_parts(key_info);
  uint length= 0;

  while (key_part < end_key_part && keypart_map)   {     length+= key_part->store_length;
    keypart_map >>= 1;
    key_part++;
  }
  return length;
}
IO Waits also are instrumented at
IO waits

MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, MAX_KEY, result, { result= rnd_pos(buf, pos); }) 
MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result, { result= index_read_map(buf, key, keypart_map, find_flag); }) 
MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, index, result, { result= index_read_idx_map(buf, index, key, keypart_map, find_flag); }) 
MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result, { result= index_next(buf); }) 
MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result, { result= index_prev(buf); }) 
MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result, { result= index_first(buf); }) 
MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result, { result= index_last(buf); }) 
MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result, { result= index_next_same(buf, key, keylen); }) 
MYSQL_TABLE_IO_WAIT(PSI_TABLE_WRITE_ROW, MAX_KEY, error, { error= write_row(buf); }) 
MYSQL_TABLE_IO_WAIT(PSI_TABLE_UPDATE_ROW, active_index, error, { error= update_row(old_data, new_data);}) 
MYSQL_TABLE_IO_WAIT(PSI_TABLE_DELETE_ROW, active_index, error, { error= delete_row(buf);}) 

MYSQL_TABLE_IO_WAIT
https://github.com/mysql/mysql-server/blob/8d8c986e5716e38cb776b627a8eee9e92241b4ce/sql/handler.cc

#define MYSQL_TABLE_IO_WAIT(OP, INDEX, RESULT, PAYLOAD)
...
case PSI_BATCH_MODE_STARTING: {
m_psi_locker = PSI_TABLE_CALL(start_table_io_wait)

PSI_TABLE_CALL
include/mysql/psi/mysql_table.h

#define PSI_TABLE_CALL(M) psi_table_service->M
psi_table_service
https://github.com/mysql/mysql-server/blob/8d8c986e5716e38cb776b627a8eee9e92241b4ce/mysys/psi_noop.cc#L536

static struct PSI_table_locker *start_table_lock_wait_noop(
struct PSI_table_locker_state *, struct PSI_table *,
enum PSI_table_lock_operation, ulong, const char *, uint) {
return nullptr;
}

...
static PSI_table_service_t psi_table_noop = {
get_table_share_noop, release_table_share_noop,
drop_table_share_noop, open_table_noop,
unbind_table_noop, rebind_table_noop,
close_table_noop, start_table_io_wait_noop,
end_table_io_wait_noop, start_table_lock_wait_noop,
end_table_lock_wait_noop, unlock_table_noop};

PSI_table_service_t *psi_table_service = &psi_table_noop;

Referensi https://fritshoogland.wordpress.com/2012/04/26/getting-to-know-Oracle-wait-events-in-linux/

Sangat
Tidak Dikategorikan



Source link

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan.