cari

Rumah  >  Soal Jawab  >  teks badan

Memanggil prosedur tersimpan jauh lebih perlahan daripada memanggil sisipan, dan sisipan pukal pada asasnya adalah sama, mengapa?

Saya mempunyai jadual dan prosedur tersimpan seperti yang ditunjukkan di bawah,

CREATE TABLE `inspect_call` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `task_id` bigint(20) unsigned NOT NULL DEFAULT '0',
  `cc_number` varchar(63) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `created_at` bigint(20) unsigned NOT NULL DEFAULT '0',
  `updated_at` bigint(20) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `task_id` (`task_id`)
) ENGINE=InnoDB AUTO_INCREMENT=234031 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 

CREATE PROCEDURE inspect_proc(IN task bigint,IN number varchar(63))
INSERT INTO inspect_call(task_id,cc_number) values (task, number)

Saya telah mengandaikan bahawa memanggil prosedur tersimpan adalah lebih pantas daripada hanya memanggil sisipan. Tetapi yang mengejutkan saya, itu tidak berlaku. Apabila saya memasukkan 10000 baris rekod, arahan sisip mengambil masa kira-kira 4 minit dan prosedur tersimpan mengambil masa kira-kira 15 minit.

Saya telah menjalankan ujian beberapa kali untuk mengesahkan ini. Pelayan MySQL bukan pelayan mewah tetapi saya tidak faham mengapa memanggil prosedur tersimpan jauh lebih perlahan.

#using mysql-connector-python 8.0.31
command = ("INSERT INTO inspect_call (task_id,cc_number)"
           "VALUES (%s, %s)")
for i in range(rows): 
    cursor.execute(command, (task_id,f"{cc}{i}"))
    # cursor.callproc("inspect_proc", (task_id,f"{cc}{i}"))
cnx.commit()

BTW, saya membaca beberapa artikel mengatakan saya boleh menetapkan innodb_flush_log_at_trx_commit = 2 untuk meningkatkan kelajuan memasukkan, tetapi saya tidak akan melakukannya.

--- Kemas kini ---

Berdasarkan jawapan yang saya dapat, saya cuba memasukkan batch (executemany) untuk melihat sama ada terdapat peningkatan, tetapi yang mengejutkan saya tidak ada .

cursor = cnx.cursor(buffered=True)
for i in range(int(rows/1000)):
    data = []
    for j in range(1000):
        data.append((task_id,f"{cc}{i*1000+j}"))
    cursor.executemany(command,data)
 cnx.commit()

 # no improvement compared to 

 cursor = cnx.cursor()
 for i in range(rows):
    cursor.execute(command, (task_id,f"{cc}{i}"))

Saya mencubanya berkali-kali (juga mencuba executemany 100 rekod dalam 1 pukulan) dan mendapati prestasi mereka pada asasnya adalah sama.

Kenapa ni?

--- Kemas kini 2 ---

Saya akhirnya faham mengapa sisipan sangat perlahan! Kerana saya menjalankan skrip dari komputer riba saya dan mengakses pangkalan data dari nama hos luarannya. Sebaik sahaja saya memuat naik skrip ke pelayan dan mengakses pangkalan data dari dalam intranet, ia adalah lebih pantas. Memasukkan 10,000 rekod mengambil masa kira-kira 3 hingga 4 saat; Kekurangan internet saya akan membuat perubahan sedemikian!

Tetapi executemany tidak meningkatkan prestasi dalam kes saya.

P粉877719694P粉877719694233 hari yang lalu397

membalas semua(1)saya akan balas

  • P粉080643975

    P粉0806439752024-03-31 00:16:22

    Contoh anda tidak mengkreditkan prosedur tersimpan kerana ia tidak mengambil kesempatan daripada mana-mana kelebihannya.

    Kelebihan utama prosedur tersimpan adalah:

    • Disusun
    • Ia menjimatkan pertukaran rangkaian (kerana pengiraan dilakukan di bahagian pelayan)

    Andaikan anda mempunyai kompleks logik yang cukup sehingga ia tidak boleh dimanipulasi melalui KEMASKINI dan anda mahu melakukannya, contohnya dalam Python, ia memerlukan:

    • Pilih baris -> Trafik Rangkaian [Pelayan -> Pelanggan]
    • Mengemas kini baris -> Agak perlahan: Python ditafsirkan, jika anda menggunakan ORM seperti SQLAlchemy (objek perlu dibuat dalam ingatan) ia mungkin lebih perlahan
    • Hantar semula baris yang dikemas kini -> Trafik rangkaian [Pelanggan -> Pelayan]

    Bayangkan contoh yang sama dilaksanakan menggunakan prosedur tersimpan. Dalam contoh seperti ini, terdapat kemungkinan besar bahawa prosedur yang disimpan akan benar-benar membuat perbezaan.

    Dalam contoh anda, anda tidak mempunyai sebarang logik, hanya memasukkan baris. Ini ialah kes penggunaan terikat I/O. Terdapat sedikit atau tiada faedah untuk mempunyai program yang disusun. Anda akan mempunyai banyak pertukaran rangkaian seperti yang anda lakukan dengan INSERT. Sama ada cara, baris mesti dihantar ke pelayan. Tiada peningkatan dalam trafik rangkaian sama ada.

    Dalam contoh anda, mungkin 批量插入 boleh membantu mencapai prestasi terbaik.

    balas
    0
  • Batalbalas