[{"data":1,"prerenderedAt":2385},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Ffind-out-why-an-excel-file-is-slow-to-open":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Ffind-out-why-an-excel-file-is-slow-to-open":2351,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Ffind-out-why-an-excel-file-is-slow-to-open":2360,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Ffind-out-why-an-excel-file-is-slow-to-open":2365,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Ffind-out-why-an-excel-file-is-slow-to-open":2366},{"id":4,"title":5,"body":6,"dateModified":2318,"datePublished":2318,"description":2319,"extension":2320,"faq":2321,"keyword":2330,"kind":2331,"meta":2332,"navigation":113,"path":2340,"seo":2341,"slug":2344,"stem":2345,"topics":2346,"type":2349,"__hash__":2350},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Ffind-out-why-an-excel-file-is-slow-to-open\u002Findex.md","Find Out Why an Excel File Is Slow to Open",{"type":7,"value":8,"toc":2306},"minimark",[9,28,33,61,70,74,77,286,313,317,329,508,529,759,763,774,1075,1091,1095,1120,1508,1544,1674,1678,1681,2088,2091,2184,2188,2234,2238,2241,2245,2251,2257,2263,2269,2273,2302],[10,11,12,13,17,18,21,22,27],"p",{},"\"The forecast workbook takes two minutes to open\" is a complaint with half a dozen usual causes, and guessing which one wastes an afternoon. Maybe a sheet's used range runs to row 1,048,576 because someone formatted whole columns; maybe the file has accumulated forty thousand cell styles from years of copy-pasting between workbooks; maybe a hundred conditional-formatting rules each cover entire columns; maybe thousands of ",[14,15,16],"code",{},"INDIRECT"," formulas recalculate on every change. An ",[14,19,20],{},".xlsx"," file is a zip archive of XML parts, so all of these leave traces that Python can measure without starting Excel. This page builds a diagnostic script that inspects the package and the sheets, then writes a one-page report ranking the likely causes. It belongs to ",[23,24,26],"a",{"href":25},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002F","Working with Large Excel Files in Python",".",[29,30,32],"h2",{"id":31},"prerequisites","Prerequisites",[34,35,40],"pre",{"className":36,"code":37,"language":38,"meta":39,"style":39},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl pandas\n","bash","",[14,41,42],{"__ignoreMap":39},[43,44,47,51,55,58],"span",{"class":45,"line":46},"line",1,[43,48,50],{"class":49},"sMTad","pip",[43,52,54],{"class":53},"srMev"," install",[43,56,57],{"class":53}," openpyxl",[43,59,60],{"class":53}," pandas\n",[10,62,63,66,67,69],{},[14,64,65],{},"forecast.xlsx"," is a deliberately unhealthy workbook: 400 rows of real data, formatting scattered down to row 60,000, a few hundred one-off font styles, 120 conditional-formatting rules over whole blocks, a validation range far larger than the data, ",[14,68,16],{}," formulas on every row and a link to another workbook. Every check below works on real files the same way.",[29,71,73],{"id":72},"step-1-what-takes-the-space-inside-the-package","Step 1 — What takes the space inside the package",[10,75,76],{},"Start with the zip archive itself. Listing its parts by uncompressed size shows immediately whether the bulk is sheet data, styles, images, pivot caches or something else:",[34,78,82],{"className":79,"code":80,"language":81,"meta":39,"style":39},"language-python shiki shiki-themes github-light github-dark-high-contrast","import zipfile\nimport pandas as pd\n\nwith zipfile.ZipFile(\"forecast.xlsx\") as z:\n    parts = pd.DataFrame([(i.filename, i.file_size, i.compress_size) for i in z.infolist()],\n                         columns=[\"part\", \"bytes\", \"compressed\"])\nparts = parts.sort_values(\"bytes\", ascending=False)\nparts[\"share %\"] = (parts[\"bytes\"] \u002F parts[\"bytes\"].sum() * 100).round(1)\nprint(parts.head(6).to_string(index=False))\n","python",[14,83,84,94,108,115,135,159,188,215,261],{"__ignoreMap":39},[43,85,86,90],{"class":45,"line":46},[43,87,89],{"class":88},"s-kum","import",[43,91,93],{"class":92},"skGVy"," zipfile\n",[43,95,97,99,102,105],{"class":45,"line":96},2,[43,98,89],{"class":88},[43,100,101],{"class":92}," pandas ",[43,103,104],{"class":88},"as",[43,106,107],{"class":92}," pd\n",[43,109,111],{"class":45,"line":110},3,[43,112,114],{"emptyLinePlaceholder":113},true,"\n",[43,116,118,121,124,127,130,132],{"class":45,"line":117},4,[43,119,120],{"class":88},"with",[43,122,123],{"class":92}," zipfile.ZipFile(",[43,125,126],{"class":53},"\"forecast.xlsx\"",[43,128,129],{"class":92},") ",[43,131,104],{"class":88},[43,133,134],{"class":92}," z:\n",[43,136,138,141,144,147,150,153,156],{"class":45,"line":137},5,[43,139,140],{"class":92},"    parts ",[43,142,143],{"class":88},"=",[43,145,146],{"class":92}," pd.DataFrame([(i.filename, i.file_size, i.compress_size) ",[43,148,149],{"class":88},"for",[43,151,152],{"class":92}," i ",[43,154,155],{"class":88},"in",[43,157,158],{"class":92}," z.infolist()],\n",[43,160,162,166,168,171,174,177,180,182,185],{"class":45,"line":161},6,[43,163,165],{"class":164},"sa561","                         columns",[43,167,143],{"class":88},[43,169,170],{"class":92},"[",[43,172,173],{"class":53},"\"part\"",[43,175,176],{"class":92},", ",[43,178,179],{"class":53},"\"bytes\"",[43,181,176],{"class":92},[43,183,184],{"class":53},"\"compressed\"",[43,186,187],{"class":92},"])\n",[43,189,191,194,196,199,201,203,206,208,212],{"class":45,"line":190},7,[43,192,193],{"class":92},"parts ",[43,195,143],{"class":88},[43,197,198],{"class":92}," parts.sort_values(",[43,200,179],{"class":53},[43,202,176],{"class":92},[43,204,205],{"class":164},"ascending",[43,207,143],{"class":88},[43,209,211],{"class":210},"sP0c6","False",[43,213,214],{"class":92},")\n",[43,216,218,221,224,227,229,232,234,236,239,242,244,247,250,253,256,259],{"class":45,"line":217},8,[43,219,220],{"class":92},"parts[",[43,222,223],{"class":53},"\"share %\"",[43,225,226],{"class":92},"] ",[43,228,143],{"class":88},[43,230,231],{"class":92}," (parts[",[43,233,179],{"class":53},[43,235,226],{"class":92},[43,237,238],{"class":88},"\u002F",[43,240,241],{"class":92}," parts[",[43,243,179],{"class":53},[43,245,246],{"class":92},"].sum() ",[43,248,249],{"class":88},"*",[43,251,252],{"class":210}," 100",[43,254,255],{"class":92},").round(",[43,257,258],{"class":210},"1",[43,260,214],{"class":92},[43,262,264,267,270,273,276,279,281,283],{"class":45,"line":263},9,[43,265,266],{"class":210},"print",[43,268,269],{"class":92},"(parts.head(",[43,271,272],{"class":210},"6",[43,274,275],{"class":92},").to_string(",[43,277,278],{"class":164},"index",[43,280,143],{"class":88},[43,282,211],{"class":210},[43,284,285],{"class":92},"))\n",[10,287,288,289,292,293,296,297,300,301,304,305,308,309,27],{},"A healthy workbook is dominated by its sheet XML (",[14,290,291],{},"xl\u002Fworksheets\u002Fsheet1.xml"," and friends) in proportion to its data. Here the first sheet is the largest part by far, although it holds only 400 rows — a sign that something other than data is being stored there. Other parts to watch: a large ",[14,294,295],{},"xl\u002Fstyles.xml"," points to style bloat, ",[14,298,299],{},"xl\u002FpivotCache\u002F"," parts to pivot caches holding copies of source data, ",[14,302,303],{},"xl\u002Fmedia\u002F"," to images, and ",[14,306,307],{},"xl\u002FexternalLinks\u002F"," to links to other files. How to look inside the parts is covered in ",[23,310,312],{"href":311},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Finspect-the-xml-inside-an-xlsx-file-with-python\u002F","Inspect the XML Inside an xlsx File with Python",[29,314,316],{"id":315},"step-2-used-range-versus-real-data","Step 2 — Used range versus real data",[10,318,319,320,324,325,328],{},"Excel loads every row in a sheet's ",[321,322,323],"em",{},"used range"," — every row that has a value ",[321,326,327],{},"or formatting",". Compare the dimension each sheet declares with the last row that actually contains a value:",[34,330,332],{"className":79,"code":331,"language":81,"meta":39,"style":39},"from openpyxl import load_workbook\n\nwb = load_workbook(\"forecast.xlsx\")\nranges = []\nfor ws in wb.worksheets:\n    last_value_row = max((c.row for row in ws.iter_rows() for c in row if c.value is not None), default=0)\n    ranges.append({\"sheet\": ws.title, \"declared\": ws.dimensions, \"max_row\": ws.max_row,\n                   \"last row with a value\": last_value_row,\n                   \"empty rows carried\": ws.max_row - last_value_row})\nprint(pd.DataFrame(ranges).to_string(index=False))\n",[14,333,334,347,351,365,375,387,447,470,478,492],{"__ignoreMap":39},[43,335,336,339,342,344],{"class":45,"line":46},[43,337,338],{"class":88},"from",[43,340,341],{"class":92}," openpyxl ",[43,343,89],{"class":88},[43,345,346],{"class":92}," load_workbook\n",[43,348,349],{"class":45,"line":96},[43,350,114],{"emptyLinePlaceholder":113},[43,352,353,356,358,361,363],{"class":45,"line":110},[43,354,355],{"class":92},"wb ",[43,357,143],{"class":88},[43,359,360],{"class":92}," load_workbook(",[43,362,126],{"class":53},[43,364,214],{"class":92},[43,366,367,370,372],{"class":45,"line":117},[43,368,369],{"class":92},"ranges ",[43,371,143],{"class":88},[43,373,374],{"class":92}," []\n",[43,376,377,379,382,384],{"class":45,"line":137},[43,378,149],{"class":88},[43,380,381],{"class":92}," ws ",[43,383,155],{"class":88},[43,385,386],{"class":92}," wb.worksheets:\n",[43,388,389,392,394,397,400,402,405,407,410,412,415,417,419,422,425,428,431,434,437,440,442,445],{"class":45,"line":161},[43,390,391],{"class":92},"    last_value_row ",[43,393,143],{"class":88},[43,395,396],{"class":210}," max",[43,398,399],{"class":92},"((c.row ",[43,401,149],{"class":88},[43,403,404],{"class":92}," row ",[43,406,155],{"class":88},[43,408,409],{"class":92}," ws.iter_rows() ",[43,411,149],{"class":88},[43,413,414],{"class":92}," c ",[43,416,155],{"class":88},[43,418,404],{"class":92},[43,420,421],{"class":88},"if",[43,423,424],{"class":92}," c.value ",[43,426,427],{"class":88},"is",[43,429,430],{"class":88}," not",[43,432,433],{"class":210}," None",[43,435,436],{"class":92},"), ",[43,438,439],{"class":164},"default",[43,441,143],{"class":88},[43,443,444],{"class":210},"0",[43,446,214],{"class":92},[43,448,449,452,455,458,461,464,467],{"class":45,"line":190},[43,450,451],{"class":92},"    ranges.append({",[43,453,454],{"class":53},"\"sheet\"",[43,456,457],{"class":92},": ws.title, ",[43,459,460],{"class":53},"\"declared\"",[43,462,463],{"class":92},": ws.dimensions, ",[43,465,466],{"class":53},"\"max_row\"",[43,468,469],{"class":92},": ws.max_row,\n",[43,471,472,475],{"class":45,"line":217},[43,473,474],{"class":53},"                   \"last row with a value\"",[43,476,477],{"class":92},": last_value_row,\n",[43,479,480,483,486,489],{"class":45,"line":263},[43,481,482],{"class":53},"                   \"empty rows carried\"",[43,484,485],{"class":92},": ws.max_row ",[43,487,488],{"class":88},"-",[43,490,491],{"class":92}," last_value_row})\n",[43,493,495,497,500,502,504,506],{"class":45,"line":494},10,[43,496,266],{"class":210},[43,498,499],{"class":92},"(pd.DataFrame(ranges).to_string(",[43,501,278],{"class":164},[43,503,143],{"class":88},[43,505,211],{"class":210},[43,507,285],{"class":92},[10,509,510,511,514,515,519,520,524,525,528],{},"The Forecast sheet's data ends at row 401, but its declared dimension is ",[14,512,513],{},"A1:H60000",": almost 60,000 rows that contain nothing but formatting, which openpyxl reports as 59,599 empty rows carried. Excel has to load, lay out and keep every one of them, and every whole-column operation then covers them too. This is the single most common cause of slow, oversized workbooks, and the fix is simple — delete the empty rows below the data (and columns to the right), which removes their formatting. ",[23,516,518],{"href":517},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fdelete-empty-rows-and-columns-with-openpyxl\u002F","Delete Empty Rows and Columns with openpyxl"," shows how, and ",[23,521,523],{"href":522},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-max-row-counting-empty-rows\u002F","Fix openpyxl max_row Counting Empty Rows"," explains why ",[14,526,527],{},"max_row"," reports the larger figure.",[530,531,539,540,539,544,539,548,539,555,539,564,539,568,539,575,539,579,539,583,539,587,539,591,539,595,539,599,539,603,539,607,539,611,539,615,539,620,539,624,539,626,539,629,539,631,539,634,539,636,539,639,539,641,539,644,539,647,539,651,539,653,539,656,539,658,539,661,539,663,539,666,539,668,539,670,539,672,539,675,539,678,539,682,539,684,539,687,539,689,539,692,539,694,539,697,539,699,539,701,539,705,539,709,539,712,539,716,539,718,539,721,539,723,539,725,539,727,539,731,539,735,539,738,539,742,539,744,539,746,539,748,539,750,539,752,539,754,539,756],"svg",{"viewBox":532,"role":533,"ariaLabelledBy":534,"xmlns":537,"style":538},"143 0 473 196","img",[535,536],"slow-range-t","slow-range-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:473px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[541,542,543],"title",{"id":535},"Data ends at row 401, the used range does not",[545,546,547],"desc",{"id":536},"The Forecast sheet holds values in rows 1 to 401. Below that, formatted cells and rule ranges continue down to row 60,000, so the used range covers sixty thousand rows although only four hundred contain data.",[549,550],"rect",{"x":551,"y":444,"width":552,"height":553,"fill":554},"143","473","196","#ffffff",[549,556],{"x":557,"y":558,"width":559,"height":560,"rx":444,"fill":561,"stroke":562,"style":563},"159.6","16.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[549,565],{"x":566,"y":558,"width":567,"height":560,"rx":444,"fill":561,"stroke":562,"style":563},"191.6","102.7",[569,570,574],"text",{"x":571,"y":572,"style":573},"242.9","33.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[549,576],{"x":577,"y":558,"width":578,"height":560,"rx":444,"fill":561,"stroke":562,"style":563},"294.2","85.8",[569,580,582],{"x":581,"y":572,"style":573},"337.1","B",[549,584],{"x":585,"y":558,"width":586,"height":560,"rx":444,"fill":561,"stroke":562,"style":563},"380.0","61.4",[569,588,590],{"x":589,"y":572,"style":573},"410.7","C",[549,592],{"x":593,"y":558,"width":594,"height":560,"rx":444,"fill":561,"stroke":562,"style":563},"441.4","52.1",[569,596,598],{"x":597,"y":572,"style":573},"467.5","D",[549,600],{"x":601,"y":558,"width":602,"height":560,"rx":444,"fill":561,"stroke":562,"style":563},"493.6","106.9",[569,604,606],{"x":605,"y":572,"style":573},"547.0","E",[549,608],{"x":557,"y":609,"width":559,"height":610,"rx":444,"fill":561,"stroke":562,"style":563},"40.0","28.0",[569,612,258],{"x":613,"y":614,"style":573},"175.6","59.0",[549,616],{"x":566,"y":609,"width":567,"height":610,"rx":444,"fill":617,"stroke":618,"style":619},"#f0f4ff","var(--brand,#5b5cf0)","stroke-width:1.5px",[569,621,623],{"x":571,"y":614,"style":622},"font-size:10.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Row",[549,625],{"x":577,"y":609,"width":578,"height":610,"rx":444,"fill":617,"stroke":618,"style":619},[569,627,628],{"x":581,"y":614,"style":622},"Month",[549,630],{"x":585,"y":609,"width":586,"height":610,"rx":444,"fill":617,"stroke":618,"style":619},[569,632,633],{"x":589,"y":614,"style":622},"Region",[549,635],{"x":593,"y":609,"width":594,"height":610,"rx":444,"fill":617,"stroke":618,"style":619},[569,637,638],{"x":597,"y":614,"style":622},"Units",[549,640],{"x":601,"y":609,"width":602,"height":610,"rx":444,"fill":617,"stroke":618,"style":619},[569,642,643],{"x":605,"y":614,"style":622},"Note",[549,645],{"x":557,"y":646,"width":559,"height":610,"rx":444,"fill":561,"stroke":562,"style":563},"68.0",[569,648,650],{"x":613,"y":649,"style":573},"87.0","2",[549,652],{"x":566,"y":646,"width":567,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[569,654,650],{"x":571,"y":649,"style":655},"font-size:10.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[549,657],{"x":577,"y":646,"width":578,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[569,659,660],{"x":581,"y":649,"style":655},"2026-03",[549,662],{"x":585,"y":646,"width":586,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[569,664,665],{"x":589,"y":649,"style":655},"South",[549,667],{"x":593,"y":646,"width":594,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[569,669,650],{"x":597,"y":649,"style":655},[549,671],{"x":601,"y":646,"width":602,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[569,673,674],{"x":605,"y":649,"style":655},"data",[549,676],{"x":557,"y":677,"width":559,"height":610,"rx":444,"fill":561,"stroke":562,"style":563},"96.0",[569,679,681],{"x":613,"y":680,"style":573},"115.0","3",[549,683],{"x":566,"y":677,"width":567,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[569,685,686],{"x":571,"y":680,"style":655},"401",[549,688],{"x":577,"y":677,"width":578,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[569,690,691],{"x":581,"y":680,"style":655},"2026-06",[549,693],{"x":585,"y":677,"width":586,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[569,695,696],{"x":589,"y":680,"style":655},"North",[549,698],{"x":593,"y":677,"width":594,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[569,700,258],{"x":597,"y":680,"style":655},[549,702],{"x":601,"y":677,"width":602,"height":610,"rx":444,"fill":703,"stroke":704,"style":619},"#d9f4f1","var(--teal,#0f9488)",[569,706,708],{"x":605,"y":680,"style":707},"font-size:10.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","last value",[549,710],{"x":557,"y":711,"width":559,"height":610,"rx":444,"fill":561,"stroke":562,"style":563},"124.0",[569,713,715],{"x":613,"y":714,"style":573},"143.0","4",[549,717],{"x":566,"y":711,"width":567,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[569,719,720],{"x":571,"y":714,"style":655},"402 … 60,000",[549,722],{"x":577,"y":711,"width":578,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[549,724],{"x":585,"y":711,"width":586,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[549,726],{"x":593,"y":711,"width":594,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[549,728],{"x":601,"y":711,"width":602,"height":610,"rx":444,"fill":729,"stroke":730,"style":619},"#fce9e9","var(--danger,#dc2626)",[569,732,734],{"x":605,"y":714,"style":733},"font-size:10.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","formatting only",[549,736],{"x":557,"y":737,"width":559,"height":610,"rx":444,"fill":561,"stroke":562,"style":563},"152.0",[569,739,741],{"x":613,"y":740,"style":573},"171.0","5",[549,743],{"x":566,"y":737,"width":567,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[569,745,323],{"x":571,"y":740,"style":655},[549,747],{"x":577,"y":737,"width":578,"height":610,"rx":444,"fill":729,"stroke":730,"style":619},[569,749,513],{"x":581,"y":740,"style":733},[549,751],{"x":585,"y":737,"width":586,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[549,753],{"x":593,"y":737,"width":594,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[549,755],{"x":601,"y":737,"width":602,"height":610,"rx":444,"fill":554,"stroke":562,"style":563},[569,757,758],{"x":605,"y":740,"style":655},"≈ 150× the data",[29,760,762],{"id":761},"step-3-styles-rules-and-validations","Step 3 — Styles, rules and validations",[10,764,765,766,769,770,773],{},"Every distinct combination of font, fill, border, alignment and number format is a separate ",[321,767,768],{},"cell style"," in ",[14,771,772],{},"styles.xml",". Workbooks that receive pasted content from many sources accumulate thousands, and Excel slows down well before its limit of 64,000. Count them, together with conditional-formatting rules and data validations and the cells they cover:",[34,775,777],{"className":79,"code":776,"language":81,"meta":39,"style":39},"from openpyxl.utils.cell import range_boundaries\n\ndef area(ref):\n    total = 0\n    for part in str(ref).split():\n        c1, r1, c2, r2 = range_boundaries(part)\n        total += (c2 - c1 + 1) * (r2 - r1 + 1)\n    return total\n\nprint(\"cell styles in workbook:\", len(wb._cell_styles))\nfor ws in wb.worksheets:\n    cf_rules = sum(len(rules) for rules in ws.conditional_formatting._cf_rules.values())\n    cf_cells = sum(area(cf.sqref) * len(rules) for cf, rules in ws.conditional_formatting._cf_rules.items())\n    dv_cells = sum(area(dv.sqref) for dv in ws.data_validations.dataValidation)\n    print(f\"{ws.title:9} CF rules: {cf_rules:4}  CF cell-evaluations: {cf_cells:>10,}  validated cells: {dv_cells:>8,}\")\n",[14,778,779,791,795,807,817,833,843,883,891,895,913,924,952,982,1005],{"__ignoreMap":39},[43,780,781,783,786,788],{"class":45,"line":46},[43,782,338],{"class":88},[43,784,785],{"class":92}," openpyxl.utils.cell ",[43,787,89],{"class":88},[43,789,790],{"class":92}," range_boundaries\n",[43,792,793],{"class":45,"line":96},[43,794,114],{"emptyLinePlaceholder":113},[43,796,797,800,804],{"class":45,"line":110},[43,798,799],{"class":88},"def",[43,801,803],{"class":802},"s_Opv"," area",[43,805,806],{"class":92},"(ref):\n",[43,808,809,812,814],{"class":45,"line":117},[43,810,811],{"class":92},"    total ",[43,813,143],{"class":88},[43,815,816],{"class":210}," 0\n",[43,818,819,822,825,827,830],{"class":45,"line":137},[43,820,821],{"class":88},"    for",[43,823,824],{"class":92}," part ",[43,826,155],{"class":88},[43,828,829],{"class":210}," str",[43,831,832],{"class":92},"(ref).split():\n",[43,834,835,838,840],{"class":45,"line":161},[43,836,837],{"class":92},"        c1, r1, c2, r2 ",[43,839,143],{"class":88},[43,841,842],{"class":92}," range_boundaries(part)\n",[43,844,845,848,851,854,856,859,862,865,867,869,872,874,877,879,881],{"class":45,"line":190},[43,846,847],{"class":92},"        total ",[43,849,850],{"class":88},"+=",[43,852,853],{"class":92}," (c2 ",[43,855,488],{"class":88},[43,857,858],{"class":92}," c1 ",[43,860,861],{"class":88},"+",[43,863,864],{"class":210}," 1",[43,866,129],{"class":92},[43,868,249],{"class":88},[43,870,871],{"class":92}," (r2 ",[43,873,488],{"class":88},[43,875,876],{"class":92}," r1 ",[43,878,861],{"class":88},[43,880,864],{"class":210},[43,882,214],{"class":92},[43,884,885,888],{"class":45,"line":217},[43,886,887],{"class":88},"    return",[43,889,890],{"class":92}," total\n",[43,892,893],{"class":45,"line":263},[43,894,114],{"emptyLinePlaceholder":113},[43,896,897,899,902,905,907,910],{"class":45,"line":494},[43,898,266],{"class":210},[43,900,901],{"class":92},"(",[43,903,904],{"class":53},"\"cell styles in workbook:\"",[43,906,176],{"class":92},[43,908,909],{"class":210},"len",[43,911,912],{"class":92},"(wb._cell_styles))\n",[43,914,916,918,920,922],{"class":45,"line":915},11,[43,917,149],{"class":88},[43,919,381],{"class":92},[43,921,155],{"class":88},[43,923,386],{"class":92},[43,925,927,930,932,935,937,939,942,944,947,949],{"class":45,"line":926},12,[43,928,929],{"class":92},"    cf_rules ",[43,931,143],{"class":88},[43,933,934],{"class":210}," sum",[43,936,901],{"class":92},[43,938,909],{"class":210},[43,940,941],{"class":92},"(rules) ",[43,943,149],{"class":88},[43,945,946],{"class":92}," rules ",[43,948,155],{"class":88},[43,950,951],{"class":92}," ws.conditional_formatting._cf_rules.values())\n",[43,953,955,958,960,962,965,967,970,972,974,977,979],{"class":45,"line":954},13,[43,956,957],{"class":92},"    cf_cells ",[43,959,143],{"class":88},[43,961,934],{"class":210},[43,963,964],{"class":92},"(area(cf.sqref) ",[43,966,249],{"class":88},[43,968,969],{"class":210}," len",[43,971,941],{"class":92},[43,973,149],{"class":88},[43,975,976],{"class":92}," cf, rules ",[43,978,155],{"class":88},[43,980,981],{"class":92}," ws.conditional_formatting._cf_rules.items())\n",[43,983,985,988,990,992,995,997,1000,1002],{"class":45,"line":984},14,[43,986,987],{"class":92},"    dv_cells ",[43,989,143],{"class":88},[43,991,934],{"class":210},[43,993,994],{"class":92},"(area(dv.sqref) ",[43,996,149],{"class":88},[43,998,999],{"class":92}," dv ",[43,1001,155],{"class":88},[43,1003,1004],{"class":92}," ws.data_validations.dataValidation)\n",[43,1006,1008,1011,1013,1016,1019,1023,1026,1029,1032,1035,1037,1040,1043,1045,1048,1050,1053,1056,1058,1061,1063,1066,1069,1071,1073],{"class":45,"line":1007},15,[43,1009,1010],{"class":210},"    print",[43,1012,901],{"class":92},[43,1014,1015],{"class":88},"f",[43,1017,1018],{"class":53},"\"",[43,1020,1022],{"class":1021},"sSjpA","{",[43,1024,1025],{"class":92},"ws.title",[43,1027,1028],{"class":88},":9",[43,1030,1031],{"class":1021},"}",[43,1033,1034],{"class":53}," CF rules: ",[43,1036,1022],{"class":1021},[43,1038,1039],{"class":92},"cf_rules",[43,1041,1042],{"class":88},":4",[43,1044,1031],{"class":1021},[43,1046,1047],{"class":53},"  CF cell-evaluations: ",[43,1049,1022],{"class":1021},[43,1051,1052],{"class":92},"cf_cells",[43,1054,1055],{"class":88},":>10,",[43,1057,1031],{"class":1021},[43,1059,1060],{"class":53},"  validated cells: ",[43,1062,1022],{"class":1021},[43,1064,1065],{"class":92},"dv_cells",[43,1067,1068],{"class":88},":>8,",[43,1070,1031],{"class":1021},[43,1072,1018],{"class":53},[43,1074,214],{"class":92},[10,1076,1077,1078,1082,1083,1086,1087,1090],{},"The style count is modest here, but on files that have been through many hands it is often the first number to check — a few hundred is normal, tens of thousands is a problem. The 120 conditional-formatting rules each cover a block of 360,000 cells, so Excel has around 43 million rule evaluations to consider whenever it redraws the sheet, and the list validation spans 60,000 rows for 400 rows of data. Rules applied to whole columns or far beyond the data are a frequent result of copying formatted rows; consolidating duplicate rules and shrinking their ranges to the data usually restores speed. ",[23,1079,1081],{"href":1080},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Flist-and-remove-conditional-formatting-with-openpyxl\u002F","List and Remove Conditional Formatting with openpyxl"," covers the clean-up. (",[14,1084,1085],{},"_cell_styles"," and ",[14,1088,1089],{},"_cf_rules"," are internal openpyxl attributes; they are stable in practice but not part of the public API.)",[29,1092,1094],{"id":1093},"step-4-volatile-functions-and-external-links","Step 4 — Volatile functions and external links",[10,1096,1097,1098,1101,1102,176,1104,176,1107,176,1110,176,1113,1086,1116,1119],{},"Some functions are ",[321,1099,1100],{},"volatile",": Excel recalculates them on every change anywhere in the workbook, along with everything that depends on them. ",[14,1103,16],{},[14,1105,1106],{},"OFFSET",[14,1108,1109],{},"NOW",[14,1111,1112],{},"TODAY",[14,1114,1115],{},"RAND",[14,1117,1118],{},"RANDBETWEEN"," are the usual suspects. Count them, and find links to other files:",[34,1121,1123],{"className":79,"code":1122,"language":81,"meta":39,"style":39},"import re\n\nVOLATILE = re.compile(r\"\\b(INDIRECT|OFFSET|NOW|TODAY|RAND|RANDBETWEEN|CELL|INFO)\\s*\\(\", re.I)\nEXTERNAL = re.compile(r\"\\[[^\\]]+\\.xls[xmb]?\\]\", re.I)\nfindings = []\nfor ws in wb.worksheets:\n    formulas = [c for row in ws.iter_rows() for c in row if isinstance(c.value, str) and c.value.startswith(\"=\")]\n    vol = [c for c in formulas if VOLATILE.search(c.value)]\n    ext = [c.coordinate for c in formulas if EXTERNAL.search(c.value)]\n    findings.append({\"sheet\": ws.title, \"formulas\": len(formulas), \"volatile\": len(vol),\n                     \"volatile functions\": sorted({m.upper() for c in vol for m in VOLATILE.findall(c.value)}),\n                     \"external links\": ext})\nprint(pd.DataFrame(findings).to_string(index=False))\nwith zipfile.ZipFile(\"forecast.xlsx\") as z:\n    print(\"externalLink parts:\", [n for n in z.namelist() if \"externalLink\" in n])\n",[14,1124,1125,1132,1136,1202,1253,1262,1272,1323,1349,1374,1404,1438,1446,1461,1475],{"__ignoreMap":39},[43,1126,1127,1129],{"class":45,"line":46},[43,1128,89],{"class":88},[43,1130,1131],{"class":92}," re\n",[43,1133,1134],{"class":45,"line":96},[43,1135,114],{"emptyLinePlaceholder":113},[43,1137,1138,1141,1144,1147,1150,1152,1155,1157,1160,1162,1164,1166,1168,1170,1172,1174,1176,1178,1180,1183,1185,1188,1191,1193,1197,1199],{"class":45,"line":110},[43,1139,1140],{"class":210},"VOLATILE",[43,1142,1143],{"class":88}," =",[43,1145,1146],{"class":92}," re.compile(",[43,1148,1149],{"class":88},"r",[43,1151,1018],{"class":53},[43,1153,1154],{"class":210},"\\b(",[43,1156,16],{"class":53},[43,1158,1159],{"class":88},"|",[43,1161,1106],{"class":53},[43,1163,1159],{"class":88},[43,1165,1109],{"class":53},[43,1167,1159],{"class":88},[43,1169,1112],{"class":53},[43,1171,1159],{"class":88},[43,1173,1115],{"class":53},[43,1175,1159],{"class":88},[43,1177,1118],{"class":53},[43,1179,1159],{"class":88},[43,1181,1182],{"class":53},"CELL",[43,1184,1159],{"class":88},[43,1186,1187],{"class":53},"INFO",[43,1189,1190],{"class":210},")\\s",[43,1192,249],{"class":88},[43,1194,1196],{"class":1195},"s_b0D","\\(",[43,1198,1018],{"class":53},[43,1200,1201],{"class":92},", re.I)\n",[43,1203,1204,1207,1209,1211,1213,1215,1218,1220,1223,1226,1229,1231,1234,1237,1239,1242,1244,1247,1249,1251],{"class":45,"line":117},[43,1205,1206],{"class":210},"EXTERNAL",[43,1208,1143],{"class":88},[43,1210,1146],{"class":92},[43,1212,1149],{"class":88},[43,1214,1018],{"class":53},[43,1216,1217],{"class":1195},"\\[",[43,1219,170],{"class":210},[43,1221,1222],{"class":88},"^",[43,1224,1225],{"class":1195},"\\]",[43,1227,1228],{"class":210},"]",[43,1230,861],{"class":88},[43,1232,1233],{"class":1195},"\\.",[43,1235,1236],{"class":53},"xls",[43,1238,170],{"class":210},[43,1240,1241],{"class":1021},"xmb",[43,1243,1228],{"class":210},[43,1245,1246],{"class":88},"?",[43,1248,1225],{"class":1195},[43,1250,1018],{"class":53},[43,1252,1201],{"class":92},[43,1254,1255,1258,1260],{"class":45,"line":137},[43,1256,1257],{"class":92},"findings ",[43,1259,143],{"class":88},[43,1261,374],{"class":92},[43,1263,1264,1266,1268,1270],{"class":45,"line":161},[43,1265,149],{"class":88},[43,1267,381],{"class":92},[43,1269,155],{"class":88},[43,1271,386],{"class":92},[43,1273,1274,1277,1279,1282,1284,1286,1288,1290,1292,1294,1296,1298,1300,1303,1306,1309,1311,1314,1317,1320],{"class":45,"line":190},[43,1275,1276],{"class":92},"    formulas ",[43,1278,143],{"class":88},[43,1280,1281],{"class":92}," [c ",[43,1283,149],{"class":88},[43,1285,404],{"class":92},[43,1287,155],{"class":88},[43,1289,409],{"class":92},[43,1291,149],{"class":88},[43,1293,414],{"class":92},[43,1295,155],{"class":88},[43,1297,404],{"class":92},[43,1299,421],{"class":88},[43,1301,1302],{"class":210}," isinstance",[43,1304,1305],{"class":92},"(c.value, ",[43,1307,1308],{"class":210},"str",[43,1310,129],{"class":92},[43,1312,1313],{"class":88},"and",[43,1315,1316],{"class":92}," c.value.startswith(",[43,1318,1319],{"class":53},"\"=\"",[43,1321,1322],{"class":92},")]\n",[43,1324,1325,1328,1330,1332,1334,1336,1338,1341,1343,1346],{"class":45,"line":217},[43,1326,1327],{"class":92},"    vol ",[43,1329,143],{"class":88},[43,1331,1281],{"class":92},[43,1333,149],{"class":88},[43,1335,414],{"class":92},[43,1337,155],{"class":88},[43,1339,1340],{"class":92}," formulas ",[43,1342,421],{"class":88},[43,1344,1345],{"class":210}," VOLATILE",[43,1347,1348],{"class":92},".search(c.value)]\n",[43,1350,1351,1354,1356,1359,1361,1363,1365,1367,1369,1372],{"class":45,"line":263},[43,1352,1353],{"class":92},"    ext ",[43,1355,143],{"class":88},[43,1357,1358],{"class":92}," [c.coordinate ",[43,1360,149],{"class":88},[43,1362,414],{"class":92},[43,1364,155],{"class":88},[43,1366,1340],{"class":92},[43,1368,421],{"class":88},[43,1370,1371],{"class":210}," EXTERNAL",[43,1373,1348],{"class":92},[43,1375,1376,1379,1381,1383,1386,1389,1391,1394,1397,1399,1401],{"class":45,"line":494},[43,1377,1378],{"class":92},"    findings.append({",[43,1380,454],{"class":53},[43,1382,457],{"class":92},[43,1384,1385],{"class":53},"\"formulas\"",[43,1387,1388],{"class":92},": ",[43,1390,909],{"class":210},[43,1392,1393],{"class":92},"(formulas), ",[43,1395,1396],{"class":53},"\"volatile\"",[43,1398,1388],{"class":92},[43,1400,909],{"class":210},[43,1402,1403],{"class":92},"(vol),\n",[43,1405,1406,1409,1411,1414,1417,1419,1421,1423,1426,1428,1431,1433,1435],{"class":45,"line":915},[43,1407,1408],{"class":53},"                     \"volatile functions\"",[43,1410,1388],{"class":92},[43,1412,1413],{"class":210},"sorted",[43,1415,1416],{"class":92},"({m.upper() ",[43,1418,149],{"class":88},[43,1420,414],{"class":92},[43,1422,155],{"class":88},[43,1424,1425],{"class":92}," vol ",[43,1427,149],{"class":88},[43,1429,1430],{"class":92}," m ",[43,1432,155],{"class":88},[43,1434,1345],{"class":210},[43,1436,1437],{"class":92},".findall(c.value)}),\n",[43,1439,1440,1443],{"class":45,"line":926},[43,1441,1442],{"class":53},"                     \"external links\"",[43,1444,1445],{"class":92},": ext})\n",[43,1447,1448,1450,1453,1455,1457,1459],{"class":45,"line":954},[43,1449,266],{"class":210},[43,1451,1452],{"class":92},"(pd.DataFrame(findings).to_string(",[43,1454,278],{"class":164},[43,1456,143],{"class":88},[43,1458,211],{"class":210},[43,1460,285],{"class":92},[43,1462,1463,1465,1467,1469,1471,1473],{"class":45,"line":984},[43,1464,120],{"class":88},[43,1466,123],{"class":92},[43,1468,126],{"class":53},[43,1470,129],{"class":92},[43,1472,104],{"class":88},[43,1474,134],{"class":92},[43,1476,1477,1479,1481,1484,1487,1489,1492,1494,1497,1499,1502,1505],{"class":45,"line":1007},[43,1478,1010],{"class":210},[43,1480,901],{"class":92},[43,1482,1483],{"class":53},"\"externalLink parts:\"",[43,1485,1486],{"class":92},", [n ",[43,1488,149],{"class":88},[43,1490,1491],{"class":92}," n ",[43,1493,155],{"class":88},[43,1495,1496],{"class":92}," z.namelist() ",[43,1498,421],{"class":88},[43,1500,1501],{"class":53}," \"externalLink\"",[43,1503,1504],{"class":88}," in",[43,1506,1507],{"class":92}," n])\n",[10,1509,1510,1511,1513,1514,1517,1518,1521,1522,1086,1524,1526,1527,1530,1531,1534,1535,1538,1539,1543],{},"Half of the Forecast sheet's 801 formulas use ",[14,1512,16],{},", which is volatile; in a large model, a few thousand such formulas can make every edit pause while they all recalculate. Here ",[14,1515,1516],{},"INDIRECT(\"C\"&ROW())"," simply means \"the cell in column C on this row\", which a plain ",[14,1519,1520],{},"=C2"," does without volatility — most uses of ",[14,1523,16],{},[14,1525,1106],{}," in the wild can be replaced like this, or with ",[14,1528,1529],{},"INDEX",". The formula in H1 refers to another workbook, ",[14,1532,1533],{},"Budget 2025.xlsx","; external links make Excel try to update or prompt on opening, which is slow when the linked file lives on a network share. The XML parts list may not show an ",[14,1536,1537],{},"externalLink"," part when the link was written as a plain formula, as here — that is why the formulas are scanned too. ",[23,1540,1542],{"href":1541},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Ffind-external-links-and-broken-references-in-a-workbook\u002F","Find External Links and Broken References in a Workbook"," goes further.",[530,1545,539,1551,539,1554,539,1557,539,1561,539,1565,539,1570,539,1576,539,1579,539,1583,539,1587,539,1591,539,1593,539,1598,539,1600,539,1603,539,1606,539,1610,539,1612,539,1616,539,1618,539,1621,539,1623,539,1627,539,1629,539,1633,539,1635,539,1638,539,1641,539,1645,539,1647,539,1651,539,1653,539,1656,539,1659,539,1663,539,1665,539,1669,539,1671],{"viewBox":1546,"role":533,"ariaLabelledBy":1547,"xmlns":537,"style":1550},"4 0 752 242",[1548,1549],"slow-causes-t","slow-causes-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[541,1552,1553],{"id":1548},"The usual causes and how they show up",[545,1555,1556],{"id":1549},"A bloated used range shows as a large sheet part and a max row far beyond the data. Style bloat shows as a large styles part and thousands of cell styles. Rule bloat shows as many conditional formatting rules over huge ranges. Volatile formulas show as INDIRECT, OFFSET or NOW in formulas. External links show as bracketed file names in formulas or externalLink parts.",[549,1558],{"x":715,"y":444,"width":1559,"height":1560,"fill":554},"752","242",[549,1562],{"x":1563,"y":558,"width":1564,"height":609,"rx":444,"fill":554,"stroke":562,"style":563},"20.0","135.3",[549,1566],{"x":1567,"y":558,"width":1568,"height":609,"rx":444,"fill":617,"stroke":618,"style":1569},"155.3","292.4","stroke-width:1.2px",[569,1571,1575],{"x":1572,"y":1573,"style":1574},"301.4","41.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","symptom in the file",[549,1577],{"x":1578,"y":558,"width":1568,"height":609,"rx":444,"fill":617,"stroke":618,"style":1569},"447.6",[569,1580,1582],{"x":1581,"y":1573,"style":1574},"593.8","fix",[549,1584],{"x":1563,"y":1585,"width":1564,"height":1586,"rx":444,"fill":561,"stroke":562,"style":563},"56.0","34.0",[569,1588,323],{"x":559,"y":1589,"style":1590},"78.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:start",[549,1592],{"x":1567,"y":1585,"width":1568,"height":1586,"rx":444,"fill":554,"stroke":562,"style":563},[569,1594,1597],{"x":1572,"y":1595,"style":1596},"77.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","max_row ≫ last value row",[549,1599],{"x":1578,"y":1585,"width":1568,"height":1586,"rx":444,"fill":554,"stroke":562,"style":563},[569,1601,1602],{"x":1581,"y":1595,"style":1596},"delete empty rows and columns",[549,1604],{"x":1563,"y":1605,"width":1564,"height":1586,"rx":444,"fill":561,"stroke":562,"style":563},"90.0",[569,1607,1609],{"x":559,"y":1608,"style":1590},"112.0","style bloat",[549,1611],{"x":1567,"y":1605,"width":1568,"height":1586,"rx":444,"fill":554,"stroke":562,"style":563},[569,1613,1615],{"x":1572,"y":1614,"style":1596},"111.0","thousands of cell styles",[549,1617],{"x":1578,"y":1605,"width":1568,"height":1586,"rx":444,"fill":554,"stroke":562,"style":563},[569,1619,1620],{"x":1581,"y":1614,"style":1596},"clear formats, use named styles",[549,1622],{"x":1563,"y":711,"width":1564,"height":1586,"rx":444,"fill":561,"stroke":562,"style":563},[569,1624,1626],{"x":559,"y":1625,"style":1590},"146.0","rule bloat",[549,1628],{"x":1567,"y":711,"width":1568,"height":1586,"rx":444,"fill":554,"stroke":562,"style":563},[569,1630,1632],{"x":1572,"y":1631,"style":1596},"145.0","many CF rules × huge ranges",[549,1634],{"x":1578,"y":711,"width":1568,"height":1586,"rx":444,"fill":554,"stroke":562,"style":563},[569,1636,1637],{"x":1581,"y":1631,"style":1596},"merge rules, shrink ranges",[549,1639],{"x":1563,"y":1640,"width":1564,"height":1586,"rx":444,"fill":561,"stroke":562,"style":563},"158.0",[569,1642,1644],{"x":559,"y":1643,"style":1590},"180.0","volatile formulas",[549,1646],{"x":1567,"y":1640,"width":1568,"height":1586,"rx":444,"fill":554,"stroke":562,"style":563},[569,1648,1650],{"x":1572,"y":1649,"style":1596},"179.0","INDIRECT, OFFSET, NOW",[549,1652],{"x":1578,"y":1640,"width":1568,"height":1586,"rx":444,"fill":554,"stroke":562,"style":563},[569,1654,1655],{"x":1581,"y":1649,"style":1596},"replace with direct refs or INDEX",[549,1657],{"x":1563,"y":1658,"width":1564,"height":1586,"rx":444,"fill":561,"stroke":562,"style":563},"192.0",[569,1660,1662],{"x":559,"y":1661,"style":1590},"214.0","external links",[549,1664],{"x":1567,"y":1658,"width":1568,"height":1586,"rx":444,"fill":554,"stroke":562,"style":563},[569,1666,1668],{"x":1572,"y":1667,"style":1596},"213.0","[Book.xlsx] in formulas",[549,1670],{"x":1578,"y":1658,"width":1568,"height":1586,"rx":444,"fill":554,"stroke":562,"style":563},[569,1672,1673],{"x":1581,"y":1667,"style":1596},"break or convert to values",[29,1675,1677],{"id":1676},"step-5-a-ranked-diagnosis-sheet","Step 5 — A ranked diagnosis sheet",[10,1679,1680],{},"Pull the findings together into one workbook a colleague can act on — each potential cause with its measured value, a threshold, and a verdict:",[34,1682,1684],{"className":79,"code":1683,"language":81,"meta":39,"style":39},"ws = wb[\"Forecast\"]\ncf_cells = sum(area(cf.sqref) * len(rules) for cf, rules in ws.conditional_formatting._cf_rules.items())\nchecks = [\n    (\"Empty rows carried in used range\", ranges[0][\"empty rows carried\"], 1_000),\n    (\"Cell styles in workbook\", len(wb._cell_styles), 4_000),\n    (\"Conditional-format cell evaluations\", cf_cells, 1_000_000),\n    (\"Validated cells beyond data\", sum(area(dv.sqref) for dv in ws.data_validations.dataValidation) - 400, 10_000),\n    (\"Volatile formulas\", findings[0][\"volatile\"], 200),\n    (\"Formulas linking to other workbooks\", len(findings[0][\"external links\"]), 0),\n]\nreport = pd.DataFrame(checks, columns=[\"Check\", \"Found\", \"Threshold\"])\nreport[\"Verdict\"] = [\"fix\" if f > t else \"ok\" for f, t in zip(report[\"Found\"], report[\"Threshold\"])]\nreport[\"Severity\"] = (report[\"Found\"] \u002F report[\"Threshold\"].replace(0, 1)).round(1)\nreport = report.sort_values([\"Verdict\", \"Severity\"], ascending=[True, False])\nreport.to_excel(\"forecast_diagnosis.xlsx\", index=False)\nprint(report.to_string(index=False))\n",[14,1685,1686,1702,1727,1737,1765,1784,1799,1834,1857,1885,1889,1921,1981,2022,2054,2072],{"__ignoreMap":39},[43,1687,1688,1691,1693,1696,1699],{"class":45,"line":46},[43,1689,1690],{"class":92},"ws ",[43,1692,143],{"class":88},[43,1694,1695],{"class":92}," wb[",[43,1697,1698],{"class":53},"\"Forecast\"",[43,1700,1701],{"class":92},"]\n",[43,1703,1704,1707,1709,1711,1713,1715,1717,1719,1721,1723,1725],{"class":45,"line":96},[43,1705,1706],{"class":92},"cf_cells ",[43,1708,143],{"class":88},[43,1710,934],{"class":210},[43,1712,964],{"class":92},[43,1714,249],{"class":88},[43,1716,969],{"class":210},[43,1718,941],{"class":92},[43,1720,149],{"class":88},[43,1722,976],{"class":92},[43,1724,155],{"class":88},[43,1726,981],{"class":92},[43,1728,1729,1732,1734],{"class":45,"line":110},[43,1730,1731],{"class":92},"checks ",[43,1733,143],{"class":88},[43,1735,1736],{"class":92}," [\n",[43,1738,1739,1742,1745,1748,1750,1753,1756,1759,1762],{"class":45,"line":117},[43,1740,1741],{"class":92},"    (",[43,1743,1744],{"class":53},"\"Empty rows carried in used range\"",[43,1746,1747],{"class":92},", ranges[",[43,1749,444],{"class":210},[43,1751,1752],{"class":92},"][",[43,1754,1755],{"class":53},"\"empty rows carried\"",[43,1757,1758],{"class":92},"], ",[43,1760,1761],{"class":210},"1_000",[43,1763,1764],{"class":92},"),\n",[43,1766,1767,1769,1772,1774,1776,1779,1782],{"class":45,"line":137},[43,1768,1741],{"class":92},[43,1770,1771],{"class":53},"\"Cell styles in workbook\"",[43,1773,176],{"class":92},[43,1775,909],{"class":210},[43,1777,1778],{"class":92},"(wb._cell_styles), ",[43,1780,1781],{"class":210},"4_000",[43,1783,1764],{"class":92},[43,1785,1786,1788,1791,1794,1797],{"class":45,"line":161},[43,1787,1741],{"class":92},[43,1789,1790],{"class":53},"\"Conditional-format cell evaluations\"",[43,1792,1793],{"class":92},", cf_cells, ",[43,1795,1796],{"class":210},"1_000_000",[43,1798,1764],{"class":92},[43,1800,1801,1803,1806,1808,1811,1813,1815,1817,1819,1822,1824,1827,1829,1832],{"class":45,"line":190},[43,1802,1741],{"class":92},[43,1804,1805],{"class":53},"\"Validated cells beyond data\"",[43,1807,176],{"class":92},[43,1809,1810],{"class":210},"sum",[43,1812,994],{"class":92},[43,1814,149],{"class":88},[43,1816,999],{"class":92},[43,1818,155],{"class":88},[43,1820,1821],{"class":92}," ws.data_validations.dataValidation) ",[43,1823,488],{"class":88},[43,1825,1826],{"class":210}," 400",[43,1828,176],{"class":92},[43,1830,1831],{"class":210},"10_000",[43,1833,1764],{"class":92},[43,1835,1836,1838,1841,1844,1846,1848,1850,1852,1855],{"class":45,"line":217},[43,1837,1741],{"class":92},[43,1839,1840],{"class":53},"\"Volatile formulas\"",[43,1842,1843],{"class":92},", findings[",[43,1845,444],{"class":210},[43,1847,1752],{"class":92},[43,1849,1396],{"class":53},[43,1851,1758],{"class":92},[43,1853,1854],{"class":210},"200",[43,1856,1764],{"class":92},[43,1858,1859,1861,1864,1866,1868,1871,1873,1875,1878,1881,1883],{"class":45,"line":263},[43,1860,1741],{"class":92},[43,1862,1863],{"class":53},"\"Formulas linking to other workbooks\"",[43,1865,176],{"class":92},[43,1867,909],{"class":210},[43,1869,1870],{"class":92},"(findings[",[43,1872,444],{"class":210},[43,1874,1752],{"class":92},[43,1876,1877],{"class":53},"\"external links\"",[43,1879,1880],{"class":92},"]), ",[43,1882,444],{"class":210},[43,1884,1764],{"class":92},[43,1886,1887],{"class":45,"line":494},[43,1888,1701],{"class":92},[43,1890,1891,1894,1896,1899,1902,1904,1906,1909,1911,1914,1916,1919],{"class":45,"line":915},[43,1892,1893],{"class":92},"report ",[43,1895,143],{"class":88},[43,1897,1898],{"class":92}," pd.DataFrame(checks, ",[43,1900,1901],{"class":164},"columns",[43,1903,143],{"class":88},[43,1905,170],{"class":92},[43,1907,1908],{"class":53},"\"Check\"",[43,1910,176],{"class":92},[43,1912,1913],{"class":53},"\"Found\"",[43,1915,176],{"class":92},[43,1917,1918],{"class":53},"\"Threshold\"",[43,1920,187],{"class":92},[43,1922,1923,1926,1929,1931,1933,1936,1939,1942,1945,1948,1951,1954,1957,1960,1963,1965,1968,1971,1973,1976,1978],{"class":45,"line":926},[43,1924,1925],{"class":92},"report[",[43,1927,1928],{"class":53},"\"Verdict\"",[43,1930,226],{"class":92},[43,1932,143],{"class":88},[43,1934,1935],{"class":92}," [",[43,1937,1938],{"class":53},"\"fix\"",[43,1940,1941],{"class":88}," if",[43,1943,1944],{"class":92}," f ",[43,1946,1947],{"class":88},">",[43,1949,1950],{"class":92}," t ",[43,1952,1953],{"class":88},"else",[43,1955,1956],{"class":53}," \"ok\"",[43,1958,1959],{"class":88}," for",[43,1961,1962],{"class":92}," f, t ",[43,1964,155],{"class":88},[43,1966,1967],{"class":210}," zip",[43,1969,1970],{"class":92},"(report[",[43,1972,1913],{"class":53},[43,1974,1975],{"class":92},"], report[",[43,1977,1918],{"class":53},[43,1979,1980],{"class":92},"])]\n",[43,1982,1983,1985,1988,1990,1992,1995,1997,1999,2001,2004,2006,2009,2011,2013,2015,2018,2020],{"class":45,"line":954},[43,1984,1925],{"class":92},[43,1986,1987],{"class":53},"\"Severity\"",[43,1989,226],{"class":92},[43,1991,143],{"class":88},[43,1993,1994],{"class":92}," (report[",[43,1996,1913],{"class":53},[43,1998,226],{"class":92},[43,2000,238],{"class":88},[43,2002,2003],{"class":92}," report[",[43,2005,1918],{"class":53},[43,2007,2008],{"class":92},"].replace(",[43,2010,444],{"class":210},[43,2012,176],{"class":92},[43,2014,258],{"class":210},[43,2016,2017],{"class":92},")).round(",[43,2019,258],{"class":210},[43,2021,214],{"class":92},[43,2023,2024,2026,2028,2031,2033,2035,2037,2039,2041,2043,2045,2048,2050,2052],{"class":45,"line":984},[43,2025,1893],{"class":92},[43,2027,143],{"class":88},[43,2029,2030],{"class":92}," report.sort_values([",[43,2032,1928],{"class":53},[43,2034,176],{"class":92},[43,2036,1987],{"class":53},[43,2038,1758],{"class":92},[43,2040,205],{"class":164},[43,2042,143],{"class":88},[43,2044,170],{"class":92},[43,2046,2047],{"class":210},"True",[43,2049,176],{"class":92},[43,2051,211],{"class":210},[43,2053,187],{"class":92},[43,2055,2056,2059,2062,2064,2066,2068,2070],{"class":45,"line":1007},[43,2057,2058],{"class":92},"report.to_excel(",[43,2060,2061],{"class":53},"\"forecast_diagnosis.xlsx\"",[43,2063,176],{"class":92},[43,2065,278],{"class":164},[43,2067,143],{"class":88},[43,2069,211],{"class":210},[43,2071,214],{"class":92},[43,2073,2075,2077,2080,2082,2084,2086],{"class":45,"line":2074},16,[43,2076,266],{"class":210},[43,2078,2079],{"class":92},"(report.to_string(",[43,2081,278],{"class":164},[43,2083,143],{"class":88},[43,2085,211],{"class":210},[43,2087,285],{"class":92},[10,2089,2090],{},"Each check is compared with a rough threshold beyond which it typically hurts, and the list is sorted so the most severe problems come first. The thresholds are rules of thumb, not hard limits — a workbook with 3,000 styles and nothing else wrong may be fine — but the ranking points the fix at the biggest cause first. For this file the bloated used range and the conditional-formatting rules lead the list, with only the style count passing; fixing those two alone usually turns a two-minute open into a few seconds. Running the same script on the \"after\" file shows whether the fix worked.",[530,2092,539,2098,539,2101,539,2104,539,2108,539,2112,539,2118,539,2122,539,2127,539,2129,539,2133,539,2136,539,2140,539,2142,539,2146,539,2151,539,2156,539,2159,539,2162,539,2165,539,2169,539,2172,539,2176,539,2179],{"viewBox":2093,"role":533,"ariaLabelledBy":2094,"xmlns":537,"style":2097},"4 0 729 220",[2095,2096],"slow-sev-t","slow-sev-d","width:100%;max-width:729px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[541,2099,2100],{"id":2095},"How far each check exceeds its threshold",[545,2102,2103],{"id":2096},"For the forecast workbook, empty rows carried in the used range are about 60 times the threshold and conditional formatting evaluations about 43 times. Validated cells beyond the data are 6 times, volatile formulas twice and external links once over. The cell style count is well within its threshold.",[549,2105],{"x":715,"y":444,"width":2106,"height":2107,"fill":554},"729","220",[549,2109],{"x":1563,"y":558,"width":2110,"height":610,"rx":2111,"fill":561,"stroke":562,"style":563},"203.5","7",[569,2113,2117],{"x":2114,"y":2115,"style":2116},"121.8","34.5","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","empty rows in used range",[549,2119],{"x":2120,"y":558,"width":2121,"height":610,"rx":2111,"fill":729,"stroke":730,"style":619},"233.5","438.6",[569,2123,2126],{"x":2124,"y":2115,"style":2125},"680.1","font-size:12px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:start","59.6×",[549,2128],{"x":1563,"y":1585,"width":2110,"height":610,"rx":2111,"fill":561,"stroke":562,"style":563},[569,2130,2132],{"x":2114,"y":2131,"style":2116},"74.5","CF cell evaluations",[549,2134],{"x":2120,"y":1585,"width":2135,"height":610,"rx":2111,"fill":729,"stroke":730,"style":619},"317.9",[569,2137,2139],{"x":2138,"y":2131,"style":2125},"559.4","43.2×",[549,2141],{"x":1563,"y":677,"width":2110,"height":610,"rx":2111,"fill":561,"stroke":562,"style":563},[569,2143,2145],{"x":2114,"y":2144,"style":2116},"114.5","validated cells beyond data",[549,2147],{"x":2120,"y":677,"width":2148,"height":610,"rx":2111,"fill":2149,"stroke":2150,"style":619},"44.1","#fdefd8","var(--gold,#b4740a)",[569,2152,2155],{"x":2153,"y":2144,"style":2154},"285.7","font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:start","6.0×",[549,2157],{"x":1563,"y":2158,"width":2110,"height":610,"rx":2111,"fill":561,"stroke":562,"style":563},"136.0",[569,2160,1644],{"x":2114,"y":2161,"style":2116},"154.5",[549,2163],{"x":2120,"y":2158,"width":2164,"height":610,"rx":2111,"fill":2149,"stroke":2150,"style":619},"14.7",[569,2166,2168],{"x":2167,"y":2161,"style":2154},"256.3","2.0×",[549,2170],{"x":1563,"y":2171,"width":2110,"height":610,"rx":2111,"fill":561,"stroke":562,"style":563},"176.0",[569,2173,2175],{"x":2114,"y":2174,"style":2116},"194.5","cell styles",[549,2177],{"x":2120,"y":2171,"width":2178,"height":610,"rx":2111,"fill":703,"stroke":704,"style":619},"6.0",[569,2180,2183],{"x":2181,"y":2174,"style":2182},"247.5","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:start","0.1× · ok",[29,2185,2187],{"id":2186},"common-pitfalls","Common pitfalls",[2189,2190,2191,2199,2208,2214,2228],"ul",{},[2192,2193,2194,2198],"li",{},[2195,2196,2197],"strong",{},"Judging by file size alone."," A small file can be slow (volatile formulas); a large one fast (plain data).",[2192,2200,2201,2207],{},[2195,2202,2203,2204,2206],{},"Trusting ",[14,2205,527],{}," as the data size."," It includes formatted empty rows.",[2192,2209,2210,2213],{},[2195,2211,2212],{},"Copying formatted rows down to the bottom of the sheet."," It extends the used range and every rule.",[2192,2215,2216,2225,2226,27],{},[2195,2217,2218,2219,2221,2222,2224],{},"Using ",[14,2220,16],{}," or ",[14,2223,1106],{}," for simple references."," They are volatile; use direct references or ",[14,2227,1529],{},[2192,2229,2230,2233],{},[2195,2231,2232],{},"Forgetting links to other workbooks."," They slow opening and may prompt users.",[29,2235,2237],{"id":2236},"conclusion","Conclusion",[10,2239,2240],{},"A slow workbook usually has a measurable cause: a used range far larger than the data, thousands of cell styles, conditional-formatting rules and validations over huge ranges, volatile functions recalculating constantly, or links to other files. Python can find each one without Excel — by sizing the parts of the zip package, comparing each sheet's dimension with its last real value, counting styles, rules and validated cells with openpyxl, and scanning formulas for volatile functions and external references. Rank the findings, fix the biggest first, and rerun the diagnosis to confirm.",[29,2242,2244],{"id":2243},"frequently-asked-questions","Frequently asked questions",[10,2246,2247,2250],{},[2195,2248,2249],{},"Why is my Excel file so slow to open?","\nThe most common causes are a used range far beyond the data because of formatting, very many cell styles, conditional formatting or validation over huge ranges, many volatile formulas such as INDIRECT or OFFSET, and links to other workbooks.",[10,2252,2253,2256],{},[2195,2254,2255],{},"How can I check an Excel file's used range with Python?","\nLoad it with openpyxl and compare ws.max_row and ws.dimensions with the last row that actually contains a value. A large gap means formatting extends far below the data.",[10,2258,2259,2262],{},[2195,2260,2261],{},"Which Excel functions are volatile?","\nINDIRECT, OFFSET, NOW, TODAY, RAND, RANDBETWEEN, CELL and INFO recalculate on every change, together with all formulas that depend on them.",[10,2264,2265,2268],{},[2195,2266,2267],{},"How do I see what takes up space in an xlsx file?","\nOpen it with Python's zipfile module and list the parts by size. The sheet XML, styles.xml, media, pivot caches and external link parts are the usual large ones.",[29,2270,2272],{"id":2271},"related","Related",[2189,2274,2275,2281,2288,2295],{},[2192,2276,2277,2278,2280],{},"Up one level: ",[23,2279,26],{"href":25}," — big files, fast code.",[2192,2282,2283,2287],{},[23,2284,2286],{"href":2285},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Freduce-the-file-size-of-an-excel-workbook-with-python\u002F","Reduce the File Size of an Excel Workbook with Python"," — fixing what this page finds.",[2192,2289,2290,2294],{},[23,2291,2293],{"href":2292},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Faudit-every-formula-in-a-workbook-with-python\u002F","Audit Every Formula in a Workbook with Python"," — a wider look at formulas.",[2192,2296,2297,2301],{},[23,2298,2300],{"href":2299},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Fspeed-up-openpyxl-with-read-only-mode\u002F","Speed Up openpyxl with Read-Only Mode"," — reading big files faster.",[2303,2304,2305],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .s_b0D, html code.shiki .s_b0D{--shiki-default:#22863A;--shiki-default-font-weight:bold;--shiki-dark:#72F088;--shiki-dark-font-weight:bold}",{"title":39,"searchDepth":96,"depth":96,"links":2307},[2308,2309,2310,2311,2312,2313,2314,2315,2316,2317],{"id":31,"depth":96,"text":32},{"id":72,"depth":96,"text":73},{"id":315,"depth":96,"text":316},{"id":761,"depth":96,"text":762},{"id":1093,"depth":96,"text":1094},{"id":1676,"depth":96,"text":1677},{"id":2186,"depth":96,"text":2187},{"id":2236,"depth":96,"text":2237},{"id":2243,"depth":96,"text":2244},{"id":2271,"depth":96,"text":2272},"2026-10-02","Diagnose a sluggish workbook from Python without opening it in Excel: which parts of the xlsx package take the space, sheets whose used range stretches far beyond the data, thousands of cell styles, piles of conditional-formatting rules and data validations, volatile functions such as INDIRECT and OFFSET, external links, and a one-page diagnosis sheet that ranks what to fix first.","md",[2322,2324,2326,2328],{"q":2249,"a":2323},"The most common causes are a used range far beyond the data because of formatting, very many cell styles, conditional formatting or validation over huge ranges, many volatile formulas such as INDIRECT or OFFSET, and links to other workbooks.",{"q":2255,"a":2325},"Load it with openpyxl and compare ws.max_row and ws.dimensions with the last row that actually contains a value. A large gap means formatting extends far below the data.",{"q":2261,"a":2327},"INDIRECT, OFFSET, NOW, TODAY, RAND, RANDBETWEEN, CELL and INFO recalculate on every change, together with all formulas that depend on them.",{"q":2267,"a":2329},"Open it with Python's zipfile module and list the parts by size. The sheet XML, styles.xml, media, pivot caches and external link parts are the usual large ones.","find out why an excel file is slow to open",null,{"breadcrumb":2333},[2334,2336,2339],{"name":2335,"item":238},"Home",{"name":2337,"item":2338},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":26,"item":25},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Ffind-out-why-an-excel-file-is-slow-to-open",{"title":2342,"description":2343},"Find Out Why an Excel File Is Slow to Open with Python","Diagnose a slow xlsx with Python: package part sizes, bloated used ranges, cell style count, conditional formatting and validation rules, volatile formulas, external links and a ranked diagnosis report.","find-out-why-an-excel-file-is-slow-to-open","advanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Ffind-out-why-an-excel-file-is-slow-to-open\u002Findex",[2347,2348],"large-files","openpyxl","how-to","wdHDdDk5pMczAAczvQ4Y_haUakJhzwli7Zj28mC3MV0",[2352,2356],{"title":2353,"path":2354,"stem":2355,"children":-1},"Count Rows in an Excel File Without Loading It","\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Fcount-rows-in-an-excel-file-without-loading-it","advanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Fcount-rows-in-an-excel-file-without-loading-it\u002Findex",{"title":2357,"path":2358,"stem":2359,"children":-1},"Process Multiple Excel Files in Parallel with Python","\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Fprocess-multiple-excel-files-in-parallel-with-python","advanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Fprocess-multiple-excel-files-in-parallel-with-python\u002Findex",[2361,2363],{"path":2362,"title":2337},"\u002Fadvanced-data-transformation-and-cleaning",{"path":2364,"title":26},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python",[],[2367,2370,2373,2376,2379,2382],{"path":2368,"title":2369,"kind":2349},"\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fspeed-up-pandas-excel-reads-with-the-calamine-engine","Speed Up pandas Excel Reads with the calamine Engine",{"path":2371,"title":2372,"kind":2349},"\u002Fautomating-reporting-workflows\u002Ftesting-and-packaging-excel-automation-scripts\u002Fprofile-a-slow-excel-report-script","Profile a Slow Excel Report Script in Python",{"path":2374,"title":2375,"kind":2349},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-a-million-rows-to-excel-with-xlsxwriter-constant-memory","Write a Million Rows to Excel with xlsxwriter",{"path":2377,"title":2378,"kind":2349},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fbenchmark-python-excel-read-and-write-speed","Benchmark Python Excel Read and Write Speed",{"path":2380,"title":2381,"kind":2349},"\u002Fadvanced-data-transformation-and-cleaning\u002Fmoving-data-between-excel-and-databases\u002Fexport-a-large-database-table-to-excel-in-chunks","Export a Large Database Table to Excel in Chunks",{"path":2383,"title":2384,"kind":2349},"\u002Fadvanced-data-transformation-and-cleaning\u002Fmoving-data-between-excel-and-databases\u002Fquery-excel-files-with-sql-using-duckdb","Query Excel Files with SQL Using DuckDB",1790972106665]