一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|數據庫技術|

服務器之家 - 數據庫 - MongoDB - MongoDB游標超時問題的4種解決方法

MongoDB游標超時問題的4種解決方法

2020-05-25 15:54青南 MongoDB

這篇文章主要給大家介紹了關于MongoDB游標超時問題的4種解決方法,文中通過示例代碼介紹的非常詳細,對大家學習或者使用MongoDB具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧

當我們使用Python從MongoDB里面讀取數據時,可能會這樣寫代碼:

?
1
2
3
4
5
6
import pymongo
 
handler = pymongo.MongoClient().db.col
 
for row in handler.find():
 parse_data(row)

短短4行代碼,讀取MongoDB里面的每一行數據,然后傳入parse_data做處理。處理完成以后再讀取下一行。邏輯清晰而簡單,能有什么問題?只要parse_data(row)不報錯,這一段代碼就完美無缺。

但事實并非這樣。

你的代碼可能會在for row in handler.find()這一行報錯。它的原因,說來話長。

要解釋這個問題,我們首先就需要知道,handler.find()返回的并不是數據庫里面的數據,而是一個游標(cursor)對象。如下圖所示:

MongoDB游標超時問題的4種解決方法

只有當你使用for循環開始迭代它的時候,游標才會真正去數據庫里面讀取數據。

但是,如果每一次循環都連接數據庫,那么網絡連接會浪費大量時間。

所以pymongo會一次性獲取100行,for row in handler.find()循環第一次的時候,它會連上MongoDB,讀取一百條數據,緩存到內存中。于是第2-100次循環,數據都是直接從內存里面獲取,不會再連接數據庫。

當循環進行到底101次的時候,再一次連接數據庫,再讀取第101-200行內容……

這個邏輯非常有效地降低了網絡I/O耗時。

但是,MongoDB默認游標的超時時間是10分鐘。10分鐘之內,必需再次連接MongoDB讀取內容刷新游標時間,否則,就會導

致游標超時報錯:

pymongo.errors.CursorNotFound: cursor id 211526444773 not found

如下圖所示:

MongoDB游標超時問題的4種解決方法

所以,回到最開始的代碼中來,如果parse_data每次執行的時間超過6秒鐘,那么它執行100次的時間就會超過10分鐘。此時,當程序想讀取第101行數據的時候,程序就會報錯。

為了解決這個問題,我們有4種辦法:

  1. 修改MongoDB的配置,延長游標超時時間,并重啟MongoDB。由于生產環境的MongoDB不能隨便重啟,所以這個方案雖然有用,但是排除。
  2. 一次性把數據全部讀取下來,再做處理:
?
1
2
3
4
all_data = [row for row in handler.find()]
 
for row in all_data:
 parse(row)

這種方案的弊端也很明顯,如果數據量非常大,你不一定能全部放到內存里面。即使能夠全部放到內存中,但是列表推導式遍歷了所有數據,緊接著for循環又遍歷一次,浪費時間。

  3.讓游標每次返回的數據小于100條,這樣消費完這一批數據的時間就會小于10分鐘:

?
1
2
3
# 每次連接數據庫,只返回50行數據
for row in handler.find().batch_size(50):
 parse_data(row)

但這種方案會增加數據庫的連接次數,從而增加I/O耗時。

  4.讓游標永不超時。通過設定參數no_cursor_timeout=True,讓游標永不超時:

?
1
2
3
4
cursor = handler.find(no_cursor_timeout=True)
for row in cursor:
 parse_data(row)
cursor.close() # 一定要手動關閉游標

然而這個操作非常危險,因為如果你的Python程序因為某種原因意外停止了,這個游標就再也無法關閉了!除非重啟MongoDB,否則這些游標會一直留在MongoDB上,占用資源。

當然可能有人會說,使用try...except把讀取數據的地方包住,只要拋出了異常,在處理異常的時候關閉游標即可:

?
1
2
3
4
5
6
7
8
cursor = handler.find(no_cursor_timeout=True)
try:
 for row in cursor:
 parse_data(row)
except Exception:
 parse_exception()
finally:
 cursor.close() # 一定要手動關閉游標

其中finally里面的代碼,無論有沒有異常,都會執行。

但這樣寫會讓代碼非常難看。為了解決這個問題,我們可以使用游標的上下文管理器:

?
1
2
3
with handler.find(no_cursor_timeout=True) as cursor:
 for row in cursor:
  parse_data(row)

只要程序退出了with的縮進,游標自動就會關閉。如果程序中途報錯,游標也會關閉。

它的原理可以用下面兩段代碼來解釋:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Test:
 def __init__(self):
  self.x = 1
 
 def echo(self):
  print(self.x)
 
 def __enter__(self):
  print('進入上下文')
  return self
 
 def __exit__(self, *args):
  print('退出上下文')
  
with Test() as t:
 t.echo()
print('退出縮進')

運行效果如下圖所示:

MongoDB游標超時問題的4種解決方法

接下來在with的縮進里面人為制造異常:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Test:
 def __init__(self):
  self.x = 1
 
 def echo(self):
  print(self.x)
 
 def __enter__(self):
  print('進入上下文')
  return self
 
 def __exit__(self, *args):
  print('退出上下文')
  
with Test() as t:
 t.echo()
 1 + 'a' # 這里一定會報錯
print('退出縮進')

運行效果如下圖所示:

MongoDB游標超時問題的4種解決方法

無論在with的縮進里面發生了什么,Test這個類中的__exit__里面的代碼始終都會運行。

我們來看看pymongo的游標對象里面,__exit__是怎么寫的,如下圖所示:

MongoDB游標超時問題的4種解決方法

可以看到,這里正是關閉游標的操作。

因此,如果我們使用上下文管理器,就可以放心大膽地使用no_cursor_timeout=True參數了。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對服務器之家的支持。

原文鏈接:https://juejin.im/post/5d555eb45188255d51425bda

延伸 · 閱讀

精彩推薦
  • MongoDBMongoDB憑什么躋身數據庫排行前五

    MongoDB憑什么躋身數據庫排行前五

    MongoDB以比去年同期超出65.96分的成績繼續雄踞榜單前五,這個增幅在全榜僅次于PostgreSQL的77.99,而其相對于4月份的6.10分的增長也是僅次于微軟SQL Server排名...

    孫浩峰3892020-05-22
  • MongoDBMongodb實現定時備份與恢復的方法教程

    Mongodb實現定時備份與恢復的方法教程

    這篇文章主要給大家介紹了Mongodb實現定時備份與恢復的方法教程,文中通過示例代碼介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面...

    chenjsh364522020-05-13
  • MongoDBMongoDB安裝圖文教程

    MongoDB安裝圖文教程

    這篇文章主要為大家詳細介紹了MongoDB安裝圖文教程,分為兩大部分為大家介紹下載MongoDB和安裝MongoDB的方法,感興趣的小伙伴們可以參考一下 ...

    Yangyi.He6132020-05-07
  • MongoDB分布式文檔存儲數據庫之MongoDB分片集群的問題

    分布式文檔存儲數據庫之MongoDB分片集群的問題

    這篇文章主要介紹了分布式文檔存儲數據庫之MongoDB分片集群的問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋...

    Linux-18743072020-12-20
  • MongoDBMongoDB 內存使用情況分析

    MongoDB 內存使用情況分析

    都說 MongoDB 是個內存大戶,但是怎么知道它到底用了多少內存呢...

    MongoDB教程網10002020-09-29
  • MongoDBMongoDB中javascript腳本編程簡介和入門實例

    MongoDB中javascript腳本編程簡介和入門實例

    作為一個數據庫,MongoDB有一個很大的優勢——它使用js管理數據庫,所以也能夠使用js腳本進行復雜的管理——這種方法非常靈活 ...

    MongoDB教程網6982020-04-24
  • MongoDB遷移sqlserver數據到MongoDb的方法

    遷移sqlserver數據到MongoDb的方法

    這篇文章主要介紹了遷移sqlserver數據到MongoDb的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下...

    聽楓xl9682021-01-03
  • MongoDBmongodb基本命令實例小結

    mongodb基本命令實例小結

    這篇文章主要介紹了mongodb基本命令,結合實例形式總結分析了MongoDB數據庫切換、查看、刪除、查詢等基本命令用法與操作注意事項,需要的朋友可以參考下...

    dawn-liu3652020-05-26
主站蜘蛛池模板: 婷婷九月| 欧美人做人爱a全程免费 | 草莓秋葵菠萝蜜绿巨人污 | www.成人在线视频 | japanesexxxx日本妞| 成人福利网站 | 大团圆6全文在线阅读 | 日韩视频免费 | 午夜福利理论片在线播放 | av中文字幕在线 | 京东热在线观看 | 日本精品中文字幕在线播放 | 把老师操了 | 免费一级欧美片在线观看 | 国产午夜成人无码免费看 | 国产一区二区精品久 | 亚洲欧美一区二区三区不卡 | 99国产精品免费观看视频 | 青青国产成人久久91网 | 久久精品一卡二卡三卡四卡视频版 | 男人的天堂久久爱 | 欧美成人免费一区在线播放 | 欧美高清milf在线播放 | 175m美女被网友灌醉啪啪玩脚 | 好吊色视频988gao在线观看 | 偷偷狠狠的日日高清完整视频 | 成人影院在线观看视频 | chinesespanking网站 | 奇米影视奇米色777欧美 | 国产精品亚洲专区在线播放 | 精品免费国产 | 欧美日韩精品一区二区三区视频播放 | 国产玖玖在线 | 亚洲国产天堂综合一区 | 亚洲网站在线播放 | 十大免费批日的软件 | 精品国产成人a区在线观看 精品国产91久久久久久久 | 日本不卡免费新一二三区 | 欧美成人影院免费观 | 40岁女人三级全黄 | 消息称老熟妇乱视频一区二区 |