Python库MariaDB版本:1.1.10和1.1.12(电流)
-MariaDB服务器版本:10.3和11.7.1-rc
以下脚本提出了错误,这是当后端数据库中存储的已准备好的语句的数量超过定义限制时会产生的。
我可以再现,如果我保留了一个列表光标对象,一个每个呼叫,并且明确未关闭光标。
无论如何,由于我正在使用with block来管理光标对象,因此它应该关闭(实际上,即使我显式将
mariadb.OperationalError: Can't create more than max_prepared_stmt_count statements (current value: 16382)
添加到for for循环时,错误仍然存在)。
(该错误发生在16382呼叫Cursor.executeMany之后)
cursor.close()
import mariadb
import json
test_connection_params = {
'user': MARIADB_USERNAME,
'password': MARIADB_PASSWORD,
'host': MARIADB_HOST_ADDRESS,
'port': 3306,
'database': MARIADB_DATABASE_NAME
}
def main():
conn = mariadb.connect(**test_connection_params)
with conn.cursor() as cursor:
cursor.execute("""
CREATE TABLE IF NOT EXISTS my_table (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(128),
description VARCHAR(2000),
embedding TEXT NOT NULL
);
""")
conn.commit()
data = [(f"Product {i}", f"Description for product {i}", json.dumps([i*0.01, i*0.02, i*0.03, i*0.04])) for i in range(1_000_000)]
query = """
INSERT INTO my_table (name, description, embedding)
VALUES (?, ?, ?)
"""
chunk_size = 10
for i in range(0, len(data), chunk_size):
with conn.cursor() as cursor:
cursor.executemany(query, data[i:i + chunk_size])
conn.commit()
conn.close()
cursor.close()
conn.close()
奇怪的是,当我将代码的MariaiaDB部分包装到Python对象时,错误使用刚刚起作用的逻辑返回。
def main():
conn = mariadb.connect(**test_connection_params)
with conn.cursor() as cursor:
query = """
CREATE TABLE IF NOT EXISTS products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(128),
description VARCHAR(2000),
embedding VECTOR(4) NOT NULL
);
"""
cursor.execute(query)
conn.commit()
conn = mariadb.connect(**test_connection_params)
data = [(f"Product {i}", f"Description for product {i}", json.dumps([i*0.01, i*0.02, i*0.03, i*0.04])) for i in range(1_000_000)]
query = "INSERT INTO products (name, description, embedding) VALUES (?, ?, VEC_FromText(?))"
chunk_size = 10
for i in range(0, len(data), chunk_size):
with conn.cursor() as cursor:
cursor.executemany(query, data[i:i + chunk_size])
conn.commit()
conn.close()
浪费资源始终分配新的光标。 Mariadb的执行人()方法使用二进制协议,除了插入/替换外,还支持删除和更新(与PymySQL或MySQL Connector不起作用),可选返回 - 这取决于您的连接速度更快10倍,但也可以节省交易。 ,由于该操作将在发生错误时自动回滚。光标本身没有上下文管理器,因此至少在pymysql和mariadb中不会自动关闭它:
class DatabaseManager:
def __init__(self, config):
self.connection = mariadb.connect(**config)
def create_table_if_not_exists(self):
query = """
CREATE TABLE IF NOT EXISTS products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(128),
description VARCHAR(2000),
embedding VECTOR(4) NOT NULL
);
"""
with self.connection.cursor() as cursor:
cursor.execute(query)
self.connection.commit()
def insert_rows(self, chunk):
query = """
INSERT INTO products (name, description, embedding)
VALUES (?, ?, VEC_FromText(?))
"""
with self.connection.cursor() as cursor:
cursor.executemany(query, chunk)
def close_connection(self):
if self.connection:
self.connection.close()
def main():
db_manager = DatabaseManager(test_connection_params)
db_manager.create_table_if_not_exists()
data = [(f"Product {i}", f"Description for product {i}", json.dumps([i * 0.01, i * 0.02, i * 0.03, i * 0.04])) for i
in range(1_000_000)]
chunk_size = 10
for i in range(0, len(data), chunk_size):
db_manager.insert_rows(data[i:i + chunk_size])
db_manager.close_connection()
因此,您应该重复使用现有的光标,而不是创建一个新的光标(它分配了新的内存,也可以在客户端和服务器上分配新的语句句柄),而是重复使用现有的。