// API callback
related_results_labels_thumbs({"version":"1.0","encoding":"UTF-8","feed":{"xmlns":"http://www.w3.org/2005/Atom","xmlns$openSearch":"http://a9.com/-/spec/opensearchrss/1.0/","xmlns$blogger":"http://schemas.google.com/blogger/2008","xmlns$georss":"http://www.georss.org/georss","xmlns$gd":"http://schemas.google.com/g/2005","xmlns$thr":"http://purl.org/syndication/thread/1.0","id":{"$t":"tag:blogger.com,1999:blog-7905389674158671872"},"updated":{"$t":"2025-09-18T07:02:56.138+08:00"},"category":[{"term":"Programming"},{"term":"Culture"},{"term":"Testing"},{"term":"scrum"},{"term":"Agile"},{"term":"performance tuning"},{"term":"Book"},{"term":"Code Quality"},{"term":"Qt"},{"term":"Event Storming"},{"term":"database"},{"term":"file system"},{"term":"virtual machine"}],"title":{"type":"text","$t":"VIVOTEK Digest"},"subtitle":{"type":"html","$t":"Journey of Software Development"},"link":[{"rel":"http://schemas.google.com/g/2005#feed","type":"application/atom+xml","href":"https:\/\/blog.rd.vivotek.com\/feeds\/posts\/default"},{"rel":"self","type":"application/atom+xml","href":"https:\/\/www.blogger.com\/feeds\/7905389674158671872\/posts\/default\/-\/performance+tuning?alt=json-in-script\u0026max-results=8"},{"rel":"alternate","type":"text/html","href":"https:\/\/blog.rd.vivotek.com\/search\/label\/performance%20tuning"},{"rel":"hub","href":"http://pubsubhubbub.appspot.com/"}],"author":[{"name":{"$t":"diro"},"uri":{"$t":"http:\/\/www.blogger.com\/profile\/13292247339970268280"},"email":{"$t":"noreply@blogger.com"},"gd$image":{"rel":"http://schemas.google.com/g/2005#thumbnail","width":"16","height":"16","src":"https:\/\/img1.blogblog.com\/img\/b16-rounded.gif"}}],"generator":{"version":"7.00","uri":"http://www.blogger.com","$t":"Blogger"},"openSearch$totalResults":{"$t":"4"},"openSearch$startIndex":{"$t":"1"},"openSearch$itemsPerPage":{"$t":"8"},"entry":[{"id":{"$t":"tag:blogger.com,1999:blog-7905389674158671872.post-6912934947286812828"},"published":{"$t":"2019-04-22T11:15:00.000+08:00"},"updated":{"$t":"2019-04-29T17:09:57.493+08:00"},"category":[{"scheme":"http://www.blogger.com/atom/ns#","term":"database"},{"scheme":"http://www.blogger.com/atom/ns#","term":"performance tuning"}],"title":{"type":"text","$t":"DataMagnet Performance tuning"},"content":{"type":"html","$t":"\u003Cdiv style=\"color: #172b4d; font-size: 14px; padding: 0px;\"\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEjvDzp5wDbmPKzAsyd-CnzKKE7PQBE7ueCGckq62QjZeR2TFVdaiwIAq6MV2OPhzvi-iGzvl2mpXauVcVzqC5nfp5BQNJuMfnA0c5XCJ8ZWIg42kO2KMsj4VT7PcSG1XrPWarrZk2a6ZUfB\/s1600\/car-1574029_1920.jpg\" imageanchor=\"1\" style=\"background-color: #eeeeee; margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" data-original-height=\"900\" data-original-width=\"1600\" height=\"225\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEjvDzp5wDbmPKzAsyd-CnzKKE7PQBE7ueCGckq62QjZeR2TFVdaiwIAq6MV2OPhzvi-iGzvl2mpXauVcVzqC5nfp5BQNJuMfnA0c5XCJ8ZWIg42kO2KMsj4VT7PcSG1XrPWarrZk2a6ZUfB\/s400\/car-1574029_1920.jpg\" width=\"400\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E\u003Cbr \/\u003E\u003C\/span\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E\u003Cbr \/\u003E\u003C\/span\u003E\n\u003Cbr \/\u003E\n\u003Cblockquote class=\"tr_bq\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003EDataMagnet 是讓客戶能夠透過 HTTP POST 傳送 JSON data 並儲存各種資訊到我們的錄影軟體 VAST2, 再透過 VAST2 來搜尋內容的功能\u0026nbsp;\u003C\/span\u003E\u003C\/blockquote\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E客戶用我們的 data magnet 功能, 一天下來會有好幾萬筆的資料，\u003C\/span\u003E\u003Cspan style=\"background-color: #eeeeee;\"\u003E而且內容是夾帶著 image 的 data (base64 format)\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEjLSyzXBrFy_2-t9v5XHph9Rx1PxukG6x46QDNhnPOLm-SR6ENqhvQiywPAyvkTu_hNlqLaK0YV9Kq3KOKSaEUXMcN_B9IJIbYYr3FJuTQRWh3ksF3h1ia-s7IDuBD3WMb3EVIPYmPhVIWg\/s1600\/1.png\" imageanchor=\"1\" style=\"clear: left; float: left; margin-bottom: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" data-original-height=\"173\" data-original-width=\"1269\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEjLSyzXBrFy_2-t9v5XHph9Rx1PxukG6x46QDNhnPOLm-SR6ENqhvQiywPAyvkTu_hNlqLaK0YV9Kq3KOKSaEUXMcN_B9IJIbYYr3FJuTQRWh3ksF3h1ia-s7IDuBD3WMb3EVIPYmPhVIWg\/s1600\/1.png\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Cspan class=\"confluence-embedded-file-wrapper confluence-embedded-manual-size\" style=\"background-color: #eeeeee; display: inline-block; max-width: none; position: relative;\"\u003E\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E而如果這樣的 data 有幾百萬 or 幾千萬筆的資料在 db 裏頭，\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E雖然我們在 UI 有限制結果的筆數 (50 results\/page)，也不會針對 snapshot column 去搜尋\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E但若搜尋條件的範圍一大，例如： 1s 一筆資料，那麼半年範圍就會有高達一千五百萬筆資料，造成\u003C\/span\u003E\u003Cspan style=\"background-color: #eeeeee;\"\u003E搜尋的速度很慢。\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E而且這樣的 database size 也是很驚人的，以上面的欄位來看 (include image data: 128px*128px) ，15 million 筆數的資料就高達 60G 左右的大小。\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E\u003Cbr \/\u003E\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E所以中間我們就找了幾種作法:\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E1. Fast text search:\u0026nbsp;\u003Ca class=\"external-link\" href=\"https:\/\/blog.kapeli.com\/sqlite-fts-contains-and-suffix-matches\" rel=\"nofollow\" style=\"color: #0052cc; text-decoration-line: none;\"\u003Ehttps:\/\/blog.kapeli.com\/sqlite-fts-contains-and-suffix-matches\u003C\/a\u003E\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E這做法有幾個流程要改:\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E首先 Create Table 的方式不一樣了\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E還有 SELECT 找 string 的方式也不一樣 (match)\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E也因為我們要 search 的文字是要 match prefix, middle, postfix\u0026nbsp;\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E原本 fts 只有 prefix mapping, 而上面的 link 跟我們說可以透過 uncompress string 的方式來做到搜尋中間的字串, 但這有幾個缺點:\u003C\/span\u003E\u003C\/div\u003E\n\u003Col style=\"color: #172b4d; font-size: 14px; margin: 10px 0px 0px;\"\u003E\n\u003Cli\u003E\u003Cspan style=\"background-color: #eeeeee;\"\u003E每個 column 個都要多一個 column 來儲存 uncompress 的 string (除了不用搜尋的 snapshot \u0026amp; timestamp column), 但這會增加整個 database 的 size\u003C\/span\u003E\u003C\/li\u003E\n\u003Cli\u003E\u003Cspan style=\"background-color: #eeeeee;\"\u003Eor 要增加 compress, uncompress function 在 Create Table 時加入\u0026nbsp;\u003Ca class=\"external-link\" href=\"https:\/\/www.sqlite.org\/fts3.html#the_compress_and_uncompress_options\" rel=\"nofollow\" style=\"color: #0052cc; text-decoration-line: none;\"\u003Ehttps:\/\/www.sqlite.org\/fts3.html#the_compress_and_uncompress_options\u003C\/a\u003E\u0026nbsp;, 但這要直接使用 SQLite 的 API function, 對我們使用 Qt 包一層的 API 不好實作\u003C\/span\u003E\u003C\/li\u003E\n\u003C\/ol\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEi32GRpas3DR0AZyxuGJfjrDuMEhfx0803xIP7FSgtumVeRs6nj9bHFkjvKkgaLb5VmS8rpZsYxxojP-RJmAeSVxbynuGPu6dAo1Ni5ZRFH-teetLPAyjqiIFHPzzdfIc5muyKBmjlCYIkP\/s1600\/2.png\" imageanchor=\"1\" style=\"clear: left; float: left; margin-bottom: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" data-original-height=\"197\" data-original-width=\"1347\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEi32GRpas3DR0AZyxuGJfjrDuMEhfx0803xIP7FSgtumVeRs6nj9bHFkjvKkgaLb5VmS8rpZsYxxojP-RJmAeSVxbynuGPu6dAo1Ni5ZRFH-teetLPAyjqiIFHPzzdfIc5muyKBmjlCYIkP\/s1600\/2.png\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Cspan class=\"confluence-embedded-file-wrapper confluence-embedded-manual-size\" style=\"background-color: #eeeeee; display: inline-block; max-width: none; position: relative;\"\u003E\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E重要的是, 我們改了一版用 fts 的 table 來搜尋, 並沒有特別的好....\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E\u003Cbr \/\u003E\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E2. 後來回頭想原本的瓶頸在哪, 拆解一下傳進去的內容...\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E看到 snapshot 的 column 其實佔了 db 很大的容量\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E若少了 snapshot 這欄位, 原本的 search 數度就會很快 (5~6 個月的搜尋範圍, 搜尋某個字串, 1s 左右)\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E所以我們就把 snapshot 的 context 想辦法不要放進去 db 裡面\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan class=\"confluence-embedded-file-wrapper confluence-embedded-manual-size\" style=\"background-color: #eeeeee; display: inline-block; max-width: none; position: relative;\"\u003E\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEiahTfDg_aAM_sYIyclAi70oxGtAOUqynLajMgO_ZnOTYyPSVLgALkHu07NBqVaJnvQCEfnsMs_E-BIWUhvGTlDltVmmPr-uBlpyCqAeyc5YDfUOGctk5AEzuIi0EWjYjk2UkRoXBCeLHHq\/s1600\/3.png\" imageanchor=\"1\" style=\"clear: left; float: left; margin-bottom: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" data-original-height=\"215\" data-original-width=\"1072\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEiahTfDg_aAM_sYIyclAi70oxGtAOUqynLajMgO_ZnOTYyPSVLgALkHu07NBqVaJnvQCEfnsMs_E-BIWUhvGTlDltVmmPr-uBlpyCqAeyc5YDfUOGctk5AEzuIi0EWjYjk2UkRoXBCeLHHq\/s1600\/3.png\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E改成存 snapshot 的路徑, 而將 user 傳過得來的 snapshot data 存成 binary 的路徑\u003C\/span\u003E\u003C\/div\u003E\n\u003Cdiv style=\"color: #172b4d; font-size: 14px; margin-top: 10px; padding: 0px;\"\u003E\n\u003Cspan style=\"background-color: #eeeeee;\"\u003E這樣的好處就是搜尋速度變快好幾倍。\u003C\/span\u003E\u003C\/div\u003E\n"},"link":[{"rel":"replies","type":"application/atom+xml","href":"https:\/\/blog.rd.vivotek.com\/feeds\/6912934947286812828\/comments\/default","title":"Post Comments"},{"rel":"replies","type":"text/html","href":"https:\/\/blog.rd.vivotek.com\/2019\/04\/datamagnet-performance-tuning.html#comment-form","title":"0 Comments"},{"rel":"edit","type":"application/atom+xml","href":"https:\/\/www.blogger.com\/feeds\/7905389674158671872\/posts\/default\/6912934947286812828"},{"rel":"self","type":"application/atom+xml","href":"https:\/\/www.blogger.com\/feeds\/7905389674158671872\/posts\/default\/6912934947286812828"},{"rel":"alternate","type":"text/html","href":"https:\/\/blog.rd.vivotek.com\/2019\/04\/datamagnet-performance-tuning.html","title":"DataMagnet Performance tuning"}],"author":[{"name":{"$t":"Jack"},"uri":{"$t":"http:\/\/www.blogger.com\/profile\/07395665566315722323"},"email":{"$t":"noreply@blogger.com"},"gd$image":{"rel":"http://schemas.google.com/g/2005#thumbnail","width":"16","height":"16","src":"https:\/\/img1.blogblog.com\/img\/b16-rounded.gif"}}],"media$thumbnail":{"xmlns$media":"http://search.yahoo.com/mrss/","url":"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEjvDzp5wDbmPKzAsyd-CnzKKE7PQBE7ueCGckq62QjZeR2TFVdaiwIAq6MV2OPhzvi-iGzvl2mpXauVcVzqC5nfp5BQNJuMfnA0c5XCJ8ZWIg42kO2KMsj4VT7PcSG1XrPWarrZk2a6ZUfB\/s72-c\/car-1574029_1920.jpg","height":"72","width":"72"},"thr$total":{"$t":"0"}},{"id":{"$t":"tag:blogger.com,1999:blog-7905389674158671872.post-411755838046896127"},"published":{"$t":"2019-04-22T09:36:00.000+08:00"},"updated":{"$t":"2019-04-25T17:28:13.954+08:00"},"category":[{"scheme":"http://www.blogger.com/atom/ns#","term":"performance tuning"},{"scheme":"http://www.blogger.com/atom/ns#","term":"Qt"}],"title":{"type":"text","$t":"如何提升 QAbstractItemModel::match 的效能"},"content":{"type":"html","$t":"\u003Cscript src=\"https:\/\/cdn.jsdelivr.net\/gh\/google\/code-prettify@master\/loader\/run_prettify.js?lang=css\u0026amp;skin=Desert\"\u003E\u003C\/script\u003E\u003Cbr \/\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEgU0XRXe7fW8biqt1P1qRx2TjA_TuviJOVuhgiJD7ak6vIov3U8scBoc4bylzAlMx_X0aifDLSkWc-H_L7zlH_3jrg0FLK0obQIc1x9JhRHqYUznnENlUstybSnrQgNK8W0Cz6j_5XecNyB\/s1600\/computer-3293875_1920.jpg\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" data-original-height=\"1066\" data-original-width=\"1600\" height=\"266\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEgU0XRXe7fW8biqt1P1qRx2TjA_TuviJOVuhgiJD7ak6vIov3U8scBoc4bylzAlMx_X0aifDLSkWc-H_L7zlH_3jrg0FLK0obQIc1x9JhRHqYUznnENlUstybSnrQgNK8W0Cz6j_5XecNyB\/s400\/computer-3293875_1920.jpg\" width=\"400\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Ch2\u003E\n\u003Cspan style=\"color: red;\"\u003E\u003Cspan style=\"font-size: small;\"\u003E\u003Cbr \/\u003E\u003C\/span\u003E\u003C\/span\u003E\u003C\/h2\u003E\n\u003Cblockquote class=\"tr_bq\"\u003E\n\u003Cspan style=\"color: red;\"\u003E\u003Cspan style=\"font-size: small;\"\u003E針對常用的match role, 可利用QHash (or QMap) 多存一份, 來加快 search 效率\u003C\/span\u003E\u003C\/span\u003E\u003C\/blockquote\u003E\n我們在設計model通常都會定義一個存unique string value的IdRole當作model item的索引, 且會很頻繁對這個role作match, 從\"\u003Ca class=\"confluence-link\" data-base-url=\"https:\/\/confluence.vivotek.com\" data-linked-resource-default-alias=\"flags對QAbstractItemModel::match的效能影響\" data-linked-resource-id=\"225149110\" data-linked-resource-type=\"page\" data-linked-resource-version=\"6\" href=\"https:\/\/vvtk-digest.blogspot.com\/2019\/04\/flagsqabstractitemmodelmatch.html\"\u003Eflags對QAbstractItemModel::match的效能影響\u003C\/a\u003E\"中的實驗中可知,\u003Cbr \/\u003E\n針對string value去作match在效率上是很糟的, 所以只要model數量大到一個程度, 就會很容易使UI thread hang住. 針對這部分的參考解法大致如下,\u003Cbr \/\u003E\n\u003Col\u003E\n\u003Cli\u003Emaintain一個QHash把每個model item的IdRole value跟相對應的model index存起來\u003C\/li\u003E\n\u003Cli\u003E複寫match, 如果是是要查IdRole, 就直接從QHash找以提升效率\u003C\/li\u003E\n\u003Cli\u003E\u003Cspan style=\"color: red;\"\u003E由於QStandardItemModel::clear本身不會觸發rowsAboutToBeRemoved, 所以即使呼叫clear, 還是要主動去清掉hash\u003C\/span\u003E\u003C\/li\u003E\n\u003C\/ol\u003E\n\u003Ccode class=\"prettyprint\"\u003E#include \u0026lt;QHash\u0026gt;\u003Cbr \/\u003E\n#include \u0026lt;QModelIndex\u0026gt;\u003Cbr \/\u003E\n#include \u0026lt;QPersistentModelIndex\u0026gt;\u003Cbr \/\u003E\n#include \u0026lt;QStandardItemModel\u0026gt;\u003Cbr \/\u003E\n#include \u0026lt;QVariant\u0026gt;\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nclass MyListModel : public QStandardItemModel\u003Cbr \/\u003E\n{\u003Cbr \/\u003E\n\u0026nbsp; Q_OBJECT\u003Cbr \/\u003E\n\u003Cbr \/\u003E\npublic:\u003Cbr \/\u003E\n\u0026nbsp; enum Roles\u003Cbr \/\u003E\n\u0026nbsp; {\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; IdRole = Qt::UserRole + 1,\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; DataRole\u003Cbr \/\u003E\n\u0026nbsp; };\u003Cbr \/\u003E\n\u0026nbsp; MyListModel(QObject *parent = nullptr)\u003Cbr \/\u003E\n\u0026nbsp; {\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \/\/ 把每個model item的IdRole value存到QHash裡, key是id, value就是model index (必須用QPersistentModelIndex)\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \/\/ 如果是tree model記得要recursive把childrn也加進來, \u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \/\/ 主要是如果使用者是先把model item的children都append好, 再append本身進來的話, 只會觸發一次rowsInserted.\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; QObject::connect(this, \u0026amp;QAbstractItemModel::rowsInserted, [=](const QModelIndex \u0026amp;parent, int start, int end) {\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; for (int row = start; row \u0026lt;= end; row++)\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; {\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; auto mdIndex = index(row, 0, parent);\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; auto id = data(mdIndex, MyListModel::IdRole);\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; m_idModelIndexHash.insert(id, QPersistentModelIndex(mdIndex));\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; }\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; });\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; QObject::connect(this, \u0026amp;QAbstractItemModel::rowsAboutToBeRemoved, this, [=](const QModelIndex \u0026amp;parent, int start, int end) {\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; for (int row = start; row \u0026lt;= end; row++)\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; {\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; auto mdIndex = index(row, 0, parent);\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp;\u0026nbsp;auto id = data(mdIndex, MyListModel::IdRole);\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp;\u0026nbsp;m_idModelIndexHash.remove(id);\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; }\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; });\u003Cbr \/\u003E\n\u0026nbsp; }\u003Cbr \/\u003E\n\u0026nbsp; virtual ~MyListModel() = default;\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u0026nbsp; \/\/ 覆寫match function, 如果針對IdRole就去QHash以提升效率\u003Cbr \/\u003E\n\u0026nbsp; virtual QModelIndexList match(const QModelIndex \u0026amp;start, int role, const QVariant \u0026amp;value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const override\u003Cbr \/\u003E\n\u0026nbsp; {\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; if (role != MyListModel::IdRole)\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; {\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; return QStandardItemModel::match(start, role, value, hits, flags);\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; }\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \/\/ todo, !m_idModelIndexHash.contains just return empty can enhance performance, but m_idModelIndexHash must be 100% correct\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; if (!m_idModelIndexHash.contains(value))\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; {\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; return QModelIndexList();\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; }\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; return QModelIndexList() \u0026lt;\u0026lt; m_idModelIndexHash.value(value);\u003Cbr \/\u003E\n\u0026nbsp; }\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u0026nbsp; \/\/ 由於QStandardItemModel::clear本身不會觸發rowsAboutToBeRemoved, 所以clear記得要主動清掉hash\u003Cbr \/\u003E\n\u0026nbsp; void clearIdHash()\u003Cbr \/\u003E\n\u0026nbsp; {\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; m_idModelIndexMap.clear();\u003Cbr \/\u003E\n\u0026nbsp; }\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u0026nbsp; QHash\u0026lt;int, QByteArray\u0026gt; roleNames() const override\u003Cbr \/\u003E\n\u0026nbsp; {\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; QHash\u0026lt;int, QByteArray\u0026gt; hash;\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp;\u0026nbsp;hash[MyListModel::DataRole] = \"dataRole\";\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp;\u0026nbsp;hash[MyListModel::IdRole] = \"idRole\";\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp;\u0026nbsp;return hash;\u003Cbr \/\u003E\n\u0026nbsp; }\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nprotected:\u003Cbr \/\u003E\n\u0026nbsp; QHash\u0026lt;QVariant, QPersistentModelIndex\u0026gt; m_idModelIndexHash;\u003Cbr \/\u003E\n};\u003C\/code\u003E\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n延續\"\u003Ca class=\"confluence-link\" data-base-url=\"https:\/\/confluence.vivotek.com\" data-linked-resource-default-alias=\"flags對QAbstractItemModel::match的效能影響\" data-linked-resource-id=\"225149110\" data-linked-resource-type=\"page\" data-linked-resource-version=\"6\" href=\"https:\/\/vvtk-digest.blogspot.com\/2019\/04\/flagsqabstractitemmodelmatch.html\"\u003Eflags對QAbstractItemModel::match的效能影響\u003C\/a\u003E\"中的實驗方法,\u003Cbr \/\u003E\n如果利用QHash得到的結果如下,\u003Cbr \/\u003E\n\u003Ctable class=\"wrapped confluenceTable\"\u003E\u003Ccolgroup\u003E\u003Ccol\u003E\u003C\/col\u003E\u003Ccol\u003E\u003C\/col\u003E\u003C\/colgroup\u003E\u003Ctbody\u003E\n\u003Ctr\u003E\u003Cth class=\"confluenceTh\"\u003Ematch from\u003C\/th\u003E\u003Cth class=\"confluenceTh\"\u003Eelapsed (ms)\u003C\/th\u003E\u003C\/tr\u003E\n\u003Ctr\u003E\u003Ctd class=\"confluenceTd\"\u003EQStandardItemModel::match\u003C\/td\u003E\u003Ctd class=\"confluenceTd\"\u003E55194\u003C\/td\u003E\u003C\/tr\u003E\n\u003Ctr\u003E\u003Ctd class=\"confluenceTd\" colspan=\"1\"\u003EQHash\u003C\/td\u003E\u003Ctd class=\"confluenceTd\" colspan=\"1\"\u003E63\u003C\/td\u003E\u003C\/tr\u003E\n\u003C\/tbody\u003E\u003C\/table\u003E\n由此可見效率是大大大大提升的,\u0026nbsp;\u003Cstrong style=\"color: red;\"\u003E缺點就是你要好好管理m_idModelIndexHash,\u0026nbsp;\u003C\/strong\u003E一有差錯都會導致model行為不正確."},"link":[{"rel":"replies","type":"application/atom+xml","href":"https:\/\/blog.rd.vivotek.com\/feeds\/411755838046896127\/comments\/default","title":"Post Comments"},{"rel":"replies","type":"text/html","href":"https:\/\/blog.rd.vivotek.com\/2019\/04\/match-role-qhash-or-qmap-search.html#comment-form","title":"0 Comments"},{"rel":"edit","type":"application/atom+xml","href":"https:\/\/www.blogger.com\/feeds\/7905389674158671872\/posts\/default\/411755838046896127"},{"rel":"self","type":"application/atom+xml","href":"https:\/\/www.blogger.com\/feeds\/7905389674158671872\/posts\/default\/411755838046896127"},{"rel":"alternate","type":"text/html","href":"https:\/\/blog.rd.vivotek.com\/2019\/04\/match-role-qhash-or-qmap-search.html","title":"如何提升 QAbstractItemModel::match 的效能"}],"author":[{"name":{"$t":"Sam"},"uri":{"$t":"http:\/\/www.blogger.com\/profile\/08875986043772937726"},"email":{"$t":"noreply@blogger.com"},"gd$image":{"rel":"http://schemas.google.com/g/2005#thumbnail","width":"32","height":"32","src":"\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEh6b6igC9c9GOkfMpoXNsMMdlVBd65oi90a2wApPWHh6MuHRhFcaxWl4zV99lcqjw0_ZcPFF1sPcqVuhMeylZOg4cKjjVpMmo4ZXjYzzfMx_TH5yxI5CpMXsi-3vDlXOQ\/s220\/%E6%9C%AA%E5%91%BD%E5%90%8D.JPG"}}],"media$thumbnail":{"xmlns$media":"http://search.yahoo.com/mrss/","url":"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEgU0XRXe7fW8biqt1P1qRx2TjA_TuviJOVuhgiJD7ak6vIov3U8scBoc4bylzAlMx_X0aifDLSkWc-H_L7zlH_3jrg0FLK0obQIc1x9JhRHqYUznnENlUstybSnrQgNK8W0Cz6j_5XecNyB\/s72-c\/computer-3293875_1920.jpg","height":"72","width":"72"},"thr$total":{"$t":"0"}},{"id":{"$t":"tag:blogger.com,1999:blog-7905389674158671872.post-1986176200472376831"},"published":{"$t":"2019-04-22T09:18:00.000+08:00"},"updated":{"$t":"2019-04-25T17:28:05.889+08:00"},"category":[{"scheme":"http://www.blogger.com/atom/ns#","term":"performance tuning"},{"scheme":"http://www.blogger.com/atom/ns#","term":"Qt"}],"title":{"type":"text","$t":"flags 對 QAbstractItemModel::match 的效能影響"},"content":{"type":"html","$t":"\u003Cscript src=\"https:\/\/cdn.jsdelivr.net\/gh\/google\/code-prettify@master\/loader\/run_prettify.js?lang=css\u0026amp;skin=Desert\"\u003E\u003C\/script\u003E\u003Cbr \/\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEjwUXAiG3PrFGgJrpoAGe7BqTS9kSu6q_V2QIcuwCxhw5VYhN5SM8wGUYAAcU1Emutg5dLIV8Pjrj1mnQU9AJjt-OVKUMljDK4fd3O4mzDCC7xBP4nqtSOD5JDJxmBrQ0-Z_uisLMx7EOAR\/s1600\/joan-of-arc-206939_1920.jpg\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" data-original-height=\"1197\" data-original-width=\"1600\" height=\"298\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEjwUXAiG3PrFGgJrpoAGe7BqTS9kSu6q_V2QIcuwCxhw5VYhN5SM8wGUYAAcU1Emutg5dLIV8Pjrj1mnQU9AJjt-OVKUMljDK4fd3O4mzDCC7xBP4nqtSOD5JDJxmBrQ0-Z_uisLMx7EOAR\/s400\/joan-of-arc-206939_1920.jpg\" width=\"400\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Ch2\u003E\n\u003Cspan style=\"color: red;\"\u003E\u003Cspan style=\"font-size: small;\"\u003E\u003Cbr \/\u003E\u003C\/span\u003E\u003C\/span\u003E\u003C\/h2\u003E\n\u003Cblockquote class=\"tr_bq\"\u003E\n\u003Cspan style=\"color: red;\"\u003E\u003Cspan style=\"font-size: small;\"\u003E秘訣: flags 只要用 Qt::MatchExactly 即可, 如果是 tree model 則再加上Qt::MatchRecursive\u003C\/span\u003E\u003C\/span\u003E\u003C\/blockquote\u003E\n\u003Cbr \/\u003E\n\u003Ccode class=\"prettyprint\"\u003E\nQModelIndexList QAbstractItemModel::match(const QModelIndex \u0026amp;start, int role, const QVariant \u0026amp;value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const\u003Cbr \/\u003E\n\u003C\/code\u003E\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nQAbstractItemModel::match中 flags 參數其實是蠻巨大的.\u003Cbr \/\u003E\n一般我們在輸入這個 flags 通常都是 copy \/ paste 舊有的 code , 所以最常看到的組合就是\"\u003Cspan style=\"color: #339966;\"\u003E\u003Cstrong\u003EQt::MatchFixedString | Qt::MatchCaseSensitive | Qt::MatchRecursive\u003C\/strong\u003E\u003C\/span\u003E\"如以下所示,\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ccode class=\"prettyprint\"\u003E\u003Cbr \/\u003E\nmodel.match(model.index(0,0), IDRole, value, 1, Qt::MatchFixedString | Qt::MatchCaseSensitive | Qt::MatchRecursive);\u003Cbr \/\u003E\n\u003C\/code\u003E\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cdiv class=\"auto-cursor-target\"\u003E\n這用法如果遇到value(QVariant)原本的型別是非字串, 例如int, 會導致所有比對都會先轉型成字串再作字串比對,\u003C\/div\u003E\n這是很沒有效率的, 例如對100000筆資料的\u003Cspan style=\"color: #339966;\"\u003E\u003Cstrong\u003Elist model\u003C\/strong\u003E\u003C\/span\u003E中針對int value作match得到以下的結果,\u003Cbr \/\u003E\n\u003Ctable class=\"wrapped confluenceTable\"\u003E\u003Ccolgroup\u003E\u003Ccol\u003E\u003C\/col\u003E\u003Ccol\u003E\u003C\/col\u003E\u003C\/colgroup\u003E\u003Ctbody\u003E\n\u003Ctr\u003E\u003Cth class=\"confluenceTh\"\u003Ematch for int value flags\u003C\/th\u003E\u003Cth class=\"confluenceTh\"\u003Eelapsed (ms)\u003C\/th\u003E\u003C\/tr\u003E\n\u003Ctr\u003E\u003Ctd class=\"confluenceTd\" colspan=\"1\"\u003EQt::MatchFixedString | Qt::MatchCaseSensitive | Qt::MatchRecursive\u003C\/td\u003E\u003Ctd class=\"confluenceTd\" colspan=\"1\"\u003E125593\u003C\/td\u003E\u003C\/tr\u003E\n\u003Ctr\u003E\u003Ctd class=\"confluenceTd\"\u003EQt::MatchFixedString | Qt::MatchCaseSensitive\u003C\/td\u003E\u003Ctd class=\"confluenceTd\"\u003E120216\u003C\/td\u003E\u003C\/tr\u003E\n\u003Ctr\u003E\u003Ctd class=\"confluenceTd\"\u003EQt::\u003Cspan style=\"color: #404244;\"\u003EMatchExactly\u003C\/span\u003E\u003C\/td\u003E\u003Ctd class=\"confluenceTd\"\u003E22162\u003C\/td\u003E\u003C\/tr\u003E\n\u003C\/tbody\u003E\u003C\/table\u003E\n由此可見型別搞錯會造成的影響有多嚴重,\u003Cbr \/\u003E\n還有一點就是如果是list model的話, 就不必要下Qt::MatchRecursive, 這樣又可增進一點效能.\u003Cbr \/\u003E\n另外對string value作match得到的結果如下,\u003Cbr \/\u003E\n\u003Ctable class=\"wrapped confluenceTable\"\u003E\u003Ccolgroup\u003E\u003Ccol\u003E\u003C\/col\u003E\u003Ccol\u003E\u003C\/col\u003E\u003C\/colgroup\u003E\u003Ctbody\u003E\n\u003Ctr\u003E\u003Cth class=\"confluenceTh\"\u003Ematch for string value flags\u003C\/th\u003E\u003Cth class=\"confluenceTh\"\u003Eelapsed (ms)\u003C\/th\u003E\u003C\/tr\u003E\n\u003Ctr\u003E\u003Ctd class=\"confluenceTd\"\u003EQt::MatchFixedString | Qt::MatchCaseSensitive\u003C\/td\u003E\u003Ctd class=\"confluenceTd\"\u003E56188\u003C\/td\u003E\u003C\/tr\u003E\n\u003Ctr\u003E\u003Ctd class=\"confluenceTd\"\u003EQt::\u003Cspan style=\"color: #404244;\"\u003EMatchExactly\u003C\/span\u003E\u003C\/td\u003E\u003Ctd class=\"confluenceTd\"\u003E55194\u003C\/td\u003E\u003C\/tr\u003E\n\u003C\/tbody\u003E\u003C\/table\u003E\n於此可見, 如果match要compare的value是要完全一致的, 其實只要使用Qt::\u003Cspan style=\"color: #404244;\"\u003EMatchExactly就萬無一失了.\u003C\/span\u003E"},"link":[{"rel":"replies","type":"application/atom+xml","href":"https:\/\/blog.rd.vivotek.com\/feeds\/1986176200472376831\/comments\/default","title":"Post Comments"},{"rel":"replies","type":"text/html","href":"https:\/\/blog.rd.vivotek.com\/2019\/04\/flagsqabstractitemmodelmatch.html#comment-form","title":"0 Comments"},{"rel":"edit","type":"application/atom+xml","href":"https:\/\/www.blogger.com\/feeds\/7905389674158671872\/posts\/default\/1986176200472376831"},{"rel":"self","type":"application/atom+xml","href":"https:\/\/www.blogger.com\/feeds\/7905389674158671872\/posts\/default\/1986176200472376831"},{"rel":"alternate","type":"text/html","href":"https:\/\/blog.rd.vivotek.com\/2019\/04\/flagsqabstractitemmodelmatch.html","title":"flags 對 QAbstractItemModel::match 的效能影響"}],"author":[{"name":{"$t":"Sam"},"uri":{"$t":"http:\/\/www.blogger.com\/profile\/08875986043772937726"},"email":{"$t":"noreply@blogger.com"},"gd$image":{"rel":"http://schemas.google.com/g/2005#thumbnail","width":"32","height":"32","src":"\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEh6b6igC9c9GOkfMpoXNsMMdlVBd65oi90a2wApPWHh6MuHRhFcaxWl4zV99lcqjw0_ZcPFF1sPcqVuhMeylZOg4cKjjVpMmo4ZXjYzzfMx_TH5yxI5CpMXsi-3vDlXOQ\/s220\/%E6%9C%AA%E5%91%BD%E5%90%8D.JPG"}}],"media$thumbnail":{"xmlns$media":"http://search.yahoo.com/mrss/","url":"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEjwUXAiG3PrFGgJrpoAGe7BqTS9kSu6q_V2QIcuwCxhw5VYhN5SM8wGUYAAcU1Emutg5dLIV8Pjrj1mnQU9AJjt-OVKUMljDK4fd3O4mzDCC7xBP4nqtSOD5JDJxmBrQ0-Z_uisLMx7EOAR\/s72-c\/joan-of-arc-206939_1920.jpg","height":"72","width":"72"},"thr$total":{"$t":"0"}},{"id":{"$t":"tag:blogger.com,1999:blog-7905389674158671872.post-8142764830446227408"},"published":{"$t":"2015-04-13T16:44:00.002+08:00"},"updated":{"$t":"2015-04-13T16:56:31.467+08:00"},"category":[{"scheme":"http://www.blogger.com/atom/ns#","term":"file system"},{"scheme":"http://www.blogger.com/atom/ns#","term":"performance tuning"}],"title":{"type":"text","$t":"mkfs.ext4 -O flex_bg -G8192 is very slow"},"content":{"type":"html","$t":"\u003Cbr \/\u003E\n\u003Ch3\u003E\n\u003Cspan style=\"color: #e69138;\"\u003E前言\u003C\/span\u003E\u003C\/h3\u003E\n\u003Cbr \/\u003E\n最近在tune ext4 的格式化速度，發現ext4 有 \u003Cspan style=\"color: blue;\"\u003Eflex_bg\u003C\/span\u003E 這個 feature 可以用，就開起來測看看。關於 flex_bg 的詳細內容可以參考 \u003Ca href=\"http:\/\/blog.chinaunix.net\/uid-28989651-id-3847039.html\"\u003Eref\u003C\/a\u003E\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n概略來說就是將幾個block groups 組成一個 flex_bg\u003Cbr \/\u003E\n它會將每個 flex_bg 的 group 0 之後的 groups 的 DB bitmap, inode bitmap, inode table\u003Cbr \/\u003E\n存放到 group 0 統一管理(放不下的時候會放到下一個group)\u003Cbr \/\u003E\n存放的時候每個 DB bitmap, inode bitmap 都會佔 1 個 block, inode table 會佔 8 個 block\u003Cbr \/\u003E\n所以DB bitmap, inode bitmap, inode table 之間在開始存放的時候都隔 $GRUUP_SIZE 個blocks (-G $GRUUP_SIZE帶入)\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ch3\u003E\n\u003Cspan style=\"color: #e69138;\"\u003E測試\u003C\/span\u003E\u003C\/h3\u003E\n\u003Cbr \/\u003E\nflex_bg 預設的 group size 是 16，使用2的冪次遞增group size來測試的時候一開始一切看\u003Cbr \/\u003E\n起來都很美好，format 時間隨著group size 增加而下降。一直到 group size 指定為\u003Cbr \/\u003E\n\u003Cspan style=\"color: red;\"\u003E8192\u003C\/span\u003E的時候忽然發現 format time 暴增...\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ca href=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEhwvqJrGJvsQ_-Pci4H9C06MMV84DTDzpzACtjpRDHfyTb-cBlIcM3W2AhPwFH9Arck3xqyEOEltGMJTtf_bg1RezQe_qRCTQYHzXttoK1dDi4a5uwUMXYcNFzHHdwK2VeNCxjH_GNjwMOT\/s1600\/mkfs+flex_bg+format+time.JPG\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEhwvqJrGJvsQ_-Pci4H9C06MMV84DTDzpzACtjpRDHfyTb-cBlIcM3W2AhPwFH9Arck3xqyEOEltGMJTtf_bg1RezQe_qRCTQYHzXttoK1dDi4a5uwUMXYcNFzHHdwK2VeNCxjH_GNjwMOT\/s1600\/mkfs+flex_bg+format+time.JPG\" \/\u003E\u003C\/a\u003E\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n這真的蠻奇怪的...網路上也找不到相關的討論。於是只好自己去看 e2fsprogs 裡面關於mke2fs這一段的實作在幹嘛。\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ch3\u003E\n\u003Cspan style=\"color: #e69138;\"\u003E結論\u003C\/span\u003E\u003C\/h3\u003E\n\u003Cbr \/\u003E\n首先 在 block size 4KB 下 ext4 管理用的 bitmap 最多 可以 mapping 32K個 block (bitmap佔1個block 32k bits)\u003Cbr \/\u003E\n所以 blocks per group 最多就是 32768 (可以調小 調小有可能會造成mke2fs 在 -G4096 的時候變慢 後面說明)\u003Cbr \/\u003E\n以 8K 的 group size 配置的時候，這些metadata(DB bitmap, inode bitmap, inode table)的初始擺放位置\u003Cbr \/\u003E\n分別是第 1025, 9217, 17409 個 block (中間都間隔 8192 個 block)\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n這在放置到第 1919 個 group 的 metadata 的時候會發生一個現象\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ca href=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEhfYB_YMz-xXL7zXH9rxCFE8ocSOJNq9JU7uVSw0cpL9W9_cMYD8OIgzTjfZ1nATIJ2cYuKVRf1FxV552KlrfX25fVZVFH6PoNz7AO_pIIEWxBNtQgwc-opHJMmPoA7pHrG9al0tYKoH96e\/s1600\/mke2fs+8k+group+size.JPG\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEhfYB_YMz-xXL7zXH9rxCFE8ocSOJNq9JU7uVSw0cpL9W9_cMYD8OIgzTjfZ1nATIJ2cYuKVRf1FxV552KlrfX25fVZVFH6PoNz7AO_pIIEWxBNtQgwc-opHJMmPoA7pHrG9al0tYKoH96e\/s1600\/mke2fs+8k+group+size.JPG\" height=\"280\" width=\"400\" \/\u003E\u003C\/a\u003E\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n可以看到在配置第 1918 個 group 的 inode table 時即將超出 group 0 的邊界了(32768 blocks per group)\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n所以在配置地 1919 個 group 的 inode table 時 mke2fs 的實作方法會回頭找 free block 來\u003Cbr \/\u003E\n存放。這時候找到的是第 2945 個 block(當然如果 group 0 中都沒有 free block 放\u003Cbr \/\u003E\nmetadata 的時候 會開始往 group 1 放不過 mke2fs 的策略看來是 group 0 還有空間就先用\u003Cbr \/\u003E\ngroup 0 ... 就算最後一定不夠用如果它是接著往 group 2 放 inode table 的話 就不會有現在的問題了...)\u003Cbr \/\u003E\n這就\u003Cspan style=\"color: red;\"\u003E造成原本理想上算好間隔分散存放的 metadata 開始交錯配置了\u003C\/span\u003E。在找free block的時候\u003Cbr \/\u003E\n原本都是馬上返回下一個free block 的 function call (flexbg_offset)在開始交錯配置以後\u003Cbr \/\u003E\n都要再做一些 search 才能找到下一個可以用的blockprofile\u003Cbr \/\u003E\n整個 mke2fs 過程花最多時間也是在 \u003Cspan style=\"color: blue;\"\u003Eflexbg_offset\u003C\/span\u003E 這個 function call\u003Cbr \/\u003E\n(對 1TB 硬碟format 整個 format 過程 總共花 \u003Cspan style=\"color: red;\"\u003E126\u003C\/span\u003E 秒 其中有\u003Cspan style=\"color: red;\"\u003E121 \u003C\/span\u003E秒花在 \u003Cspan style=\"color: blue;\"\u003Eflexbg_offset\u003C\/span\u003E 的處理)\u003Cbr \/\u003E\n所以在 GROUP_SIZE 是 8192 的時候會因為這些 metadata 在 group 0 裡面配置的時候容易發生交錯放置的情況\u003Cbr \/\u003E\n以至於 mke2fs 在搜尋下一個可以放metadata 的 block 的時候 比起其他的 GROUP_SIZE 花比較多的 overhead。\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ch3\u003E\n\u003Cspan style=\"color: #e69138;\"\u003E另外\u003C\/span\u003E\u0026nbsp;\u003C\/h3\u003E\n\u003Cbr \/\u003E\n如果在 \u003Cspan style=\"color: blue;\"\u003E-G 8192\u003C\/span\u003E 的時候加上\u003Cspan style=\"color: blue;\"\u003E -b 8192\u003C\/span\u003E 的 option (指定 block size 成 8K)-\u0026gt; \u003Cbr \/\u003E\n則 -G 8192 就會變得跟 -G 4096 速度差不多。這是因為 block size 變 8K -\u0026gt; blocks per group 變 64K\u003Cbr \/\u003E\n(其實有少一些零頭 實際上是 65528個，bitmap 可以 mapping 的 block 數 變 64K )\u003Cbr \/\u003E\n則 inode table 配置的時候 不會很快遇到 group block 邊界的問題 就\u003Cspan style=\"color: blue;\"\u003E比較不會\u003C\/span\u003E發生和 DB bitmap 或 inode bitmap 交錯配置的情況"},"link":[{"rel":"replies","type":"application/atom+xml","href":"https:\/\/blog.rd.vivotek.com\/feeds\/8142764830446227408\/comments\/default","title":"Post Comments"},{"rel":"replies","type":"text/html","href":"https:\/\/blog.rd.vivotek.com\/2015\/04\/ext4-flexbg-feature.html#comment-form","title":"0 Comments"},{"rel":"edit","type":"application/atom+xml","href":"https:\/\/www.blogger.com\/feeds\/7905389674158671872\/posts\/default\/8142764830446227408"},{"rel":"self","type":"application/atom+xml","href":"https:\/\/www.blogger.com\/feeds\/7905389674158671872\/posts\/default\/8142764830446227408"},{"rel":"alternate","type":"text/html","href":"https:\/\/blog.rd.vivotek.com\/2015\/04\/ext4-flexbg-feature.html","title":"mkfs.ext4 -O flex_bg -G8192 is very slow"}],"author":[{"name":{"$t":"Unknown"},"email":{"$t":"noreply@blogger.com"},"gd$image":{"rel":"http://schemas.google.com/g/2005#thumbnail","width":"16","height":"16","src":"https:\/\/img1.blogblog.com\/img\/b16-rounded.gif"}}],"media$thumbnail":{"xmlns$media":"http://search.yahoo.com/mrss/","url":"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEhwvqJrGJvsQ_-Pci4H9C06MMV84DTDzpzACtjpRDHfyTb-cBlIcM3W2AhPwFH9Arck3xqyEOEltGMJTtf_bg1RezQe_qRCTQYHzXttoK1dDi4a5uwUMXYcNFzHHdwK2VeNCxjH_GNjwMOT\/s72-c\/mkfs+flex_bg+format+time.JPG","height":"72","width":"72"},"thr$total":{"$t":"0"}}]}});