在flask項目中,防止隨着時間的流逝,數據庫數據越來越多,導致接口訪問數據庫速度變慢。所以自己填充數據進行測試及 mysql優化
1.插入數據:
通過腳本,使用多進程,每100次提交數據
import multiprocessing import time from flask import Flask from flask_sqlalchemy import SQLAlchemy HOST = '127.0.0.1' USER = "root" PASSWD = "" DB = "fwss_dev" CHARTSET = "utf8" app = Flask(__name__, instance_relative_config=True) # 鏈接數據庫路徑 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://%s:%[email protected]:3306/%s?charset=%s' % (USER, PASSWD, DB, CHARTSET) # 如果設置成 True (默認情況),Flask-SQLAlchemy 將會追蹤對象的修改並且發送信號。這需要額外的內存, 如果不必要的可以禁用它。 app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True # 如果設置成 True,SQLAlchemy 將會記錄所有 發到標準輸出(stderr)的語句,這對調試很有幫助。 app.config['SQLALCHEMY_ECHO'] = False # 數據庫連接池的大小。默認是數據庫引擎的默認值 (通常是 5)。 app.config['SQLALCHEMY_POOL_SIZE'] = 6 db = SQLAlchemy(app) def insert(count): start = time.time() for item in range(50000): # time1 = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time_one)) print(count) for it in range(100): db.session.execute( f"""INSERT INTO order_bang (creator_id,redenvelope,status) VALUES ({count},12,0,'需要')""" # f"INSERT INTO account_realauth (uid,`status`) VALUES({count},2)" ) count += 1 db.session.commit() print((time.time() - start) / 60) if __name__ == '__main__': with app.app_context(): multiprocessing.Process(target=insert, args=(273256,)).start() multiprocessing.Process(target=insert, args=(10273256,)).start() multiprocessing.Process(target=insert, args=(20273256,)).start() multiprocessing.Process(target=insert, args=(30273256,)).start()
以上只是展示 部分插入數據庫的腳本,總共插入數據量如下: 用戶表(account_user)110萬用戶,實名認證表(account_realauth)20萬用戶,某訂單表(order_bang)2023萬條。相關表結構如下:
CREATE TABLE `order_bang` ( `id` int(11) NOT NULL AUTO_INCREMENT, `creator_id` int(11) NOT NULL, `status` tinyint(4) DEFAULT NULL, `create_time` datetime DEFAULT NULL, `province_id` char(6) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `city_id` char(4) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
........
PRIMARY KEY (`id`), KEY `ix_order_bang_province_id` (`province_id`), KEY `ix_order_bang_status` (`status`), KEY `bang_addr_index` (`province_id`,`city_id`), KEY `ix_order_bang_create_time` (`create_time`), KEY `ix_order_bang_creator_id` (`creator_id`) )
2.在flask中記錄查詢較慢的sql語句及相關信息
本人設置最長查詢時間爲0.1秒便記錄
相關 方法在:項目中記錄影響性能的緩慢數據庫查詢
3.關閉mysql緩存功能
查看緩存是否開啓,
輸入命令:show variables like '%cache%'; query_cache_type值爲OFF表示關閉
關閉方式輸入如下:
one.
set global query_cache_type=0 set global query_cache_size=0
two.
查詢中添加: Select sql_no_cache count(*) from account_user; 不緩存
4.查看相關結果,並進行優化
一:
時間耗時3.32秒。
分析得知:
where子句條件時uid進行篩選,而索引用的是 id。
解決方法:
第一種:在 uid上添加索引。
分析得知:
查詢使用uid的索引,耗時0.002秒。
第二種:對於客戶端不需要表中全部字段的情況,在查詢時最好選擇具體的字段,而不是直接 select * from table;這樣 可以減少網絡帶寬
在sqlalchemy中爲如下(直接使用類方法,及查詢具體字段,而不是返回一個對象)
class RealAuth(DB.Model):
@classmethod
def get_success_realname(cls, uid):
db_result = DB.session.query(cls.real_name).filter(
and_(cls.uid == uid, cls.status == RealAuthStatus.SUCCESS)).order_by(
cls.id.desc()).limit(1).first()
總結:
錯誤原因:由於沒有對where子句條件使用索引,導致查詢過慢
經驗教訓:添加索引
二:在查訂單時, 接口直接 無響應
sql語句如下:
索引如下:
city字段類型是 char類型
通過 explain查看本條sql,city_id傳的值是int類型:
索引使用的是 create_time。
把city_id改爲數據庫中設定的 str 類型,再次查看
總結:
錯誤原因:導致此接口查詢無響應的原因是 在 大量數據的情況下,沒有規範 書寫 sql查詢的數據類型,導致 無法使用正確的索引,而導致此問題
經驗教訓:在開發中,在sql執行之前,一定要手動的把 查詢條件的值的類型和設計表時的類型相對應,否則可能導致 數據庫無法使用此索引,而出錯。
待更新;