web-dev-qa-db-ja.com

MySQLバッファカーソルとはw.r.t python mysqlコネクタ

誰かがこれを理解するための例を挙げていただけますか?

クエリを実行した後、MySQLCursorBufferedカーソルはサーバーから結果セット全体をフェッチし、行をバッファリングします。バッファカーソルを使用して実行されるクエリの場合、fetchone()などの行フェッチメソッドは、バッファされた行のセットから行を返します。非バッファカーソルの場合、行フェッチメソッドが呼び出されるまで、サーバーから行はフェッチされません。この場合、同じ接続で他のステートメントを実行する前に、結果セットのすべての行をフェッチする必要があります。そうしないと、InternalError(未読の結果が見つかりました)例外が発生します。

ありがとう

14
gpk27

これら2つのタイプのCursorsの違いは2つ考えられます。

最初の方法は、バッファカーソルを使用してクエリを実行する場合、_MySQLCursorBuffered.rowcount_をチェックすることで返される行数を取得できることです。ただし、バッファリングされていないカーソルのrowcount属性は、executeメソッドが呼び出された直後に_-1_を返します。これは、基本的に、結果セット全体がサーバーからまだフェッチされていないことを意味します。さらに、バッファリングされていないカーソルのrowcount属性は、そこから行をフェッチするにつれて増加しますが、バッファリングされたカーソルのrowcount属性は、そこから行をフェッチするときに同じままです。

次のスニペットコードは、上記のポイントを示しています。

_import mysql.connector


conn = mysql.connector.connect(database='db',
                               user='username',
                               password='pass',
                               Host='localhost',
                               port=3306)

buffered_cursor = conn.cursor(buffered=True)
unbuffered_cursor = conn.cursor(buffered=False)

create_query = """
drop table if exists people;
create table if not exists people (
    personid int(10) unsigned auto_increment,
    firstname varchar(255),
    lastname varchar(255),
    primary key (personid)
);
insert into people (firstname, lastname)
values ('Jon', 'Bon Jovi'),
('David', 'Bryan'),
('Tico', 'Torres'),
('Phil', 'Xenidis'),
('Hugh', 'McDonald')
"""

# Create and populate a table
results = buffered_cursor.execute(create_query, multi=True)
conn.commit()

buffered_cursor.execute("select * from people")
print("Row count from a buffer cursor:", buffered_cursor.rowcount)
unbuffered_cursor.execute("select * from people")
print("Row count from an unbuffered cursor:", unbuffered_cursor.rowcount)

print()
print("Fetching rows from a buffered cursor: ")

while True:
    try:
        row = next(buffered_cursor)
        print("Row:", row)
        print("Row count:", buffered_cursor.rowcount)
    except StopIteration:
        break

print()
print("Fetching rows from an unbuffered cursor: ")

while True:
    try:
        row = next(unbuffered_cursor)
        print("Row:", row)
        print("Row count:", unbuffered_cursor.rowcount)
    except StopIteration:
        break
_

上記のスニペットは、次のようなものを返します。

_Row count from a buffered reader:  5
Row count from an unbuffered reader:  -1

Fetching rows from a buffered cursor:
Row: (1, 'Jon', 'Bon Jovi')
Row count: 5
Row: (2, 'David', 'Bryan')
Row count: 5
Row: (3, 'Tico', 'Torres')
Row count: 5
Row: (4, 'Phil', 'Xenidis')
Row count: 5
Row: (5, 'Hugh', 'McDonald')
Row: 5

Fetching rows from an unbuffered cursor:
Row: (1, 'Jon', 'Bon Jovi')
Row count: 1
Row: (2, 'David', 'Bryan')
Row count: 2
Row: (3, 'Tico', 'Torres')
Row count: 3
Row: (4, 'Phil', 'Xenidis')
Row count: 4
Row: (5, 'Hugh', 'McDonald')
Row count: 5
_

ご覧のとおり、バッファリングされていないカーソルのrowcount属性は_-1_で始まり、生成した結果をループ処理するにつれて増加します。これは、バッファカーソルには当てはまりません。

違いを確認する2番目の方法は、2つの(同じ接続の下で)executesのどちらに最初に注意するかです。行が完全にフェッチされていない非バッファカーソルの実行から始めて、バッファカーソルでクエリを実行しようとすると、InternalError例外が発生し、何を消費するか破棄するように求められますバッファリングされていないカーソルによって返されます。以下はイラストです:

_import mysql.connector


conn = mysql.connector.connect(database='db',
                               user='username',
                               password='pass',
                               Host='localhost',
                               port=3306)

buffered_cursor = conn.cursor(buffered=True)
unbuffered_cursor = conn.cursor(buffered=False)

create_query = """
drop table if exists people;
create table if not exists people (
    personid int(10) unsigned auto_increment,
    firstname varchar(255),
    lastname varchar(255),
    primary key (personid)
);
insert into people (firstname, lastname)
values ('Jon', 'Bon Jovi'),
('David', 'Bryan'),
('Tico', 'Torres'),
('Phil', 'Xenidis'),
('Hugh', 'McDonald')
"""

# Create and populate a table
results = buffered_cursor.execute(create_query, multi=True)
conn.commit()

unbuffered_cursor.execute("select * from people")
unbuffered_cursor.fetchone()
buffered_cursor.execute("select * from people")
_

上記のスニペットは、InternalError例外を発生させ、未読の結果があることを示すメッセージが表示されます。基本的に言っているのは、同じ接続でカーソルを使用して別のクエリを実行する前に、バッファなしカーソルによって返された結果を完全に消費する必要があるということです。 unbuffered_cursor.fetchone()unbuffered_cursor.fetchall()で変更すると、エラーが消えます。

メモリ消費など、他のそれほど明白ではない違いがあります。バッファリングされたカーソルは、サーバーから結果セット全体をフェッチして行をバッファリングするため、より多くのメモリを消費する可能性があります。

これがお役に立てば幸いです。

12
Abdou