Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Kesalahan saat menggunakan pymysql di labu

Pertama-tama, Anda perlu memutuskan apakah Anda ingin mempertahankan koneksi persisten ke MySQL. Yang terakhir berkinerja lebih baik, tetapi perlu sedikit perawatan.

Default wait_timeout di MySQL adalah 8 jam. Kapan pun koneksi tidak digunakan lebih lama dari wait_timeout itu tertutup. Ketika server MySQL di-restart, itu juga menutup semua koneksi yang dibuat. Jadi, jika Anda menggunakan koneksi persisten, Anda perlu memeriksa sebelum menggunakan koneksi apakah koneksi masih hidup (dan jika tidak, sambungkan kembali). Jika Anda menggunakan koneksi per permintaan, Anda tidak perlu mempertahankan status koneksi, karena koneksi selalu baru.

Koneksi per permintaan

Koneksi database non-persisten memiliki overhead yang jelas untuk membuka koneksi, handshaking, dan sebagainya (untuk server database dan klien) per setiap permintaan HTTP yang masuk.

Berikut kutipan dari tutorial resmi Flask tentang koneksi database :

Namun, perhatikan bahwa konteks aplikasi diinisialisasi per permintaan (yang agak terselubung oleh masalah efisiensi dan istilah Flask). Dan dengan demikian, itu masih sangat tidak efisien. Namun itu harus menyelesaikan masalah Anda. Berikut cuplikan yang dilucuti dari apa yang disarankan seperti yang diterapkan ke pymysql :

import pymysql
from flask import Flask, g, request    

app = Flask(__name__)    

def connect_db():
    return pymysql.connect(
        user = 'guest', password = '', database = 'sakila', 
        autocommit = True, charset = 'utf8mb4', 
        cursorclass = pymysql.cursors.DictCursor)

def get_db():
    '''Opens a new database connection per request.'''        
    if not hasattr(g, 'db'):
        g.db = connect_db()
    return g.db    

@app.teardown_appcontext
def close_db(error):
    '''Closes the database connection at the end of request.'''    
    if hasattr(g, 'db'):
        g.db.close()    

@app.route('/')
def hello_world():
    city = request.args.get('city')

    cursor = get_db().cursor()
    cursor.execute('SELECT city_id FROM city WHERE city = %s', city)
    row = cursor.fetchone()

    if row:
      return 'City "{}" is #{:d}'.format(city, row['city_id'])
    else:
      return 'City "{}" not found'.format(city)

Koneksi persisten

Untuk koneksi database koneksi persisten ada dua pilihan utama. Entah Anda memiliki kumpulan koneksi atau memetakan koneksi ke proses pekerja. Karena biasanya aplikasi Flask WSGI dilayani oleh server berulir dengan jumlah utas tetap (misalnya uWSGI), pemetaan utas lebih mudah dan efisien.

Ada sebuah paket, DBUtils , yang mengimplementasikan keduanya, dan PersistentDB untuk koneksi yang dipetakan dengan utas.

Satu peringatan penting dalam mempertahankan koneksi yang persisten adalah transaksi. API untuk koneksi ulang adalah ping . Aman untuk membuat pernyataan tunggal secara otomatis, tetapi dapat mengganggu di antara transaksi (sedikit lebih detail di sini ). DBUtils menangani ini, dan hanya boleh terhubung kembali pada dbapi.OperationalError dan dbapi.InternalError (secara default, dikendalikan oleh failures ke penginisialisasi PersistentDB ) dibangkitkan di luar transaksi.

Berikut tampilan cuplikan di atas dengan PersistentDB .

import pymysql
from flask import Flask, g, request
from DBUtils.PersistentDB import PersistentDB    

app = Flask(__name__)    

def connect_db():
    return PersistentDB(
        creator = pymysql, # the rest keyword arguments belong to pymysql
        user = 'guest', password = '', database = 'sakila', 
        autocommit = True, charset = 'utf8mb4', 
        cursorclass = pymysql.cursors.DictCursor)

def get_db():
    '''Opens a new database connection per app.'''

    if not hasattr(app, 'db'):
        app.db = connect_db()
    return app.db.connection()    

@app.route('/')
def hello_world():
    city = request.args.get('city')

    cursor = get_db().cursor()
    cursor.execute('SELECT city_id FROM city WHERE city = %s', city)
    row = cursor.fetchone()

    if row:
      return 'City "{}" is #{:d}'.format(city, row['city_id'])
    else:
      return 'City "{}" not found'.format(city)

Tolok ukur mikro

Untuk memberikan sedikit petunjuk tentang implikasi kinerja dalam angka, berikut adalah tolok ukur mikro.

Saya berlari:

  • uwsgi --http :5000 --wsgi-file app_persistent.py --callable app --master --processes 1 --threads 16
  • uwsgi --http :5000 --wsgi-file app_per_req.py --callable app --master --processes 1 --threads 16

Dan mengujinya dengan konkurensi 1, 4, 8, 16 melalui:

siege -b -t 15s -c 16 http://localhost:5000/?city=london

Pengamatan (untuk konfigurasi lokal saya):

  1. Koneksi persisten ~30% lebih cepat,
  2. Pada konkurensi 4 dan yang lebih tinggi, proses pekerja uWSGI mencapai lebih dari 100% penggunaan CPU (pymysql harus mengurai protokol MySQL dengan Python murni, yang merupakan hambatannya),
  3. Pada konkurensi 16, mysqld Utilisasi CPU adalah ~55% untuk per-permintaan dan ~45% untuk koneksi persisten.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana cara menggunakan PATCH untuk memperbarui bidang basis data sederhana?

  2. Mengapa parameter binding dalam klausa ORDER BY tidak mengurutkan hasil?

  3. Tidak dapat mengeluarkan pernyataan manipulasi data dengan executeQuery()

  4. MySQL melihat izin dan kesalahan definisi 1356

  5. Kolom 'id' tidak memiliki nilai default?