2017-10-11 93 views
4

有人可以舉個例子來理解這個嗎?什麼是mysql緩衝光標w.r.t python mysql連接器

執行查詢後,MySQLCursorBuffered光標將從服務器獲取整個結果集並緩衝行。 對於使用緩衝遊標執行的查詢,諸如fetchone()之類的抓取行的方法會從緩衝行集合中返回行。對於非緩衝遊標,直到調用行抓取方法時纔會從服務器獲取行。在這種情況下,必須確保在執行同一連接上的任何其他語句之前獲取結果集的所有行,否則會引發InternalError(未讀結果)異常。

感謝

回答

1

我能想到的兩種方式這兩種類型的Cursor s爲不同的。

第一種方法是,如果使用緩衝遊標執行查詢,則可以通過檢查MySQLCursorBuffered.rowcount來獲取返回的行數。但是,調用execute方法後,未緩衝遊標的rowcount屬性返回-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開始,隨着我們循環生成的結果而增加。緩衝光標不是這種情況。

第二種說明差異的方法是注意兩者中的哪一個(在同一連接下)execute。如果你從執行一個沒有被緩存的遊標開始,然後嘗試用緩存的遊標執行一個查詢,將會引發一個異常,並且你會被要求消耗或拋棄非緩衝遊標返回的內容。下面是一個例證:

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(),錯誤將消失。

還有其他不太明顯的差異,如內存消耗。緩衝遊標可能消耗更多內存,因爲它們從服務器獲取整個結果集並緩衝行。

我希望這證明有用。