{"id":46987,"date":"2026-09-21T18:56:45","date_gmt":"2026-09-21T16:56:45","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/?p=46987"},"modified":"2026-09-21T19:51:43","modified_gmt":"2026-09-21T17:51:43","slug":"sql-server-why-cant-i-read-the-full-table-in-parallel","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/","title":{"rendered":"SQL Server: why can&#8217;t I read the full table in parallel???"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">&#8220;<strong>Why won&#8217;t my table read in parallel???&#8221; <\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That was more or less the question <a href=\"https:\/\/www.linkedin.com\/in\/roger-schoenmann\/\" data-type=\"link\" data-id=\"https:\/\/www.linkedin.com\/in\/roger-schoenmann\/\">Roger Sch\u00f6nmann<\/a> and I were asking ourselves while staring at two execution plans on a SQL Server 2025 lab instance. The first query scanned the whole <code>Users<\/code> table of the <code>StackOverflow2010<\/code> database on a single thread and took five seconds (elapsed time). The second one scanned exactly the same pages, with a <code>WHERE<\/code> clause on <code>Location<\/code>, got a parallel plan and finished in under three hundred milliseconds.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The obvious reading is that parallelism made the difference, and that the optimizer made a poor choice by keeping the first query serial. The numbers ended up saying the opposite, including once I had forced the parallel plan by hand.<\/p>\n\n\n\n<h3 id=\"h-the-two-queries\" class=\"wp-block-heading\">The two queries<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Everything below ran on SQL Server 2025, <code>cost threshold for parallelism<\/code> left at its default of 5 (for this lab only \ud83d\ude09). The <code>Users<\/code> table holds 299\u2019398 rows on 7\u2019401 pages. Each query ran on a cold buffer pool, so both paid the same disk reads.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\nCHECKPOINT;\n\nDBCC FREEPROCCACHE; -- on a lab only\nDBCC DROPCLEANBUFFERS;  -- on a lab only\n\nSET STATISTICS IO, TIME ON;\n\nSELECT * FROM dbo.Users;\n\nSELECT * FROM dbo.Users\nWHERE Location LIKE &#039;%Denmark%&#039;;\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th><\/th><th>Scan count<\/th><th>Read-ahead reads<\/th><th>CPU<\/th><\/tr><\/thead><tbody><tr><td>No <code>WHERE<\/code><\/td><td>1<\/td><td>7\u2019401<\/td><td>1.016 s<\/td><\/tr><tr><td><code>LIKE '%Denmark%'<\/code><\/td><td>5<\/td><td>7\u2019401<\/td><td>0.266 s<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The read-ahead counts match to the page. The leading wildcard makes the predicate <strong>non-sargable<\/strong>, so the second query cannot seek and has to read every row to test it, exactly like the first one. The filter only reduces the rows returned.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The serial query needs about one second of CPU in total, so even a perfect parallel plan could only shave a fraction off it.<\/p>\n\n\n\n<h3 id=\"h-how-the-optimizer-decides\" class=\"wp-block-heading\">How the optimizer decides<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>cost threshold for parallelism<\/code> is only an entry point when the query planner is building the tree of possible execution plans. <strong><span style=\"text-decoration: underline\">When the serial plan costs more than the threshold<\/span><\/strong>, the optimizer also builds a parallel alternative, then keeps whichever of the two is cheaper. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The costing of the parallel alternative is explained in detail by <a href=\"http:\/\/dataeducation.com\/next-level-parallel-plan-forcing-an-alternative-to-8649\/\">Adam Machanic<\/a>: <strong>CPU costs are divided by the degree of parallelism, <span style=\"text-decoration: underline\">I\/O costs are not divided at all<\/span><\/strong>, and the exchange operators added to the plan <span style=\"text-decoration: underline\">come with a cost of their own<\/span>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The plan XML of the serial query gives everything needed to do the arithmetic.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\n&lt;OptimizerHardwareDependentProperties ... EstimatedAvailableDegreeOfParallelism=&quot;2&quot; ... \/&gt;\n&lt;RelOp AvgRowSize=&quot;4468&quot; EstimateCPU=&quot;0.329495&quot; EstimateIO=&quot;5.46609&quot;\n       EstimateRows=&quot;299398&quot; PhysicalOp=&quot;Clustered Index Scan&quot;\n       EstimatedTotalSubtreeCost=&quot;5.79558&quot; ... &gt;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Around <strong>90%<\/strong> of the scan cost is I\/O, which the parallel plan keeps as is. The part that can shrink is 0.33, divided by the two threads the optimizer assumes for costing on this instance, so the best a parallel scan can hope to save is roughly 0.16. In exchange, the plan needs a<code> Gather Streams <\/code>operator to bring every row back to a single thread, and here that means 299\u2019398 rows the optimizer believes to be 4\u2019468 bytes wide on average, mostly because <code>AboutMe<\/code> is an <code>nvarchar(max)<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>There was no <code>NonParallelPlanReason<\/code> in the XML, the optimization level was <code>FULL<\/code>, and nothing in the plan pointed to an inhibitor. The optimizer looked at the parallel alternative and turned it down on cost.<\/strong><\/p>\n\n\n\n<h3 id=\"h-forcing-the-parallel-plan-anyway\" class=\"wp-block-heading\">Forcing the parallel plan anyway<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Understanding the costing did not stop me from wanting to see the parallel plan run. Three attempts failed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>OPTION(QUERYTRACEON 8649, RECOMPILE)<\/code> compiled with trace flag 8649 listed under <code>IsCompileTime=\"true\"<\/code>, and the plan stayed serial with no <code>NonParallelPlanReason<\/code>. I cannot say with certainty why the flag did not win here. <code>USE HINT('ENABLE_PARALLEL_PLAN_PREFERENCE')<\/code> gave the same result.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.linkedin.com\/in\/adammachanic\/\" data-type=\"link\" data-id=\"https:\/\/www.linkedin.com\/in\/adammachanic\/\">Adam Machani<\/a><a href=\"https:\/\/www.linkedin.com\/in\/adammachanic\/\">c<\/a>&#8216;s <code><a href=\"http:\/\/dataeducation.com\/next-level-parallel-plan-forcing-an-alternative-to-8649\/\" data-type=\"link\" data-id=\"http:\/\/dataeducation.com\/next-level-parallel-plan-forcing-an-alternative-to-8649\/\">make_parallel()<\/a><\/code> function, cross applied to the query as his article describes, produced a spectacular plan with a <code>Gather Streams<\/code> estimated at 549\u2019756\u2019000\u2019000 rows. The optimizer parallelised the fake branch of the function, closed the parallel zone before its aggregate, and left the scan of <code>Users<\/code> on the outer serial Nested Loops. <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\nSELECT x.*\nFROM dbo.make_parallel() AS mp\nCROSS APPLY\n(\n    SELECT * FROM dbo.Users\n) AS x;\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"260\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-22-1024x260.png\" alt=\"\" class=\"wp-image-47008\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-22-1024x260.png 1024w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-22-300x76.png 300w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-22-765x194.png 765w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-22.png 1159w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">What finally worked was going after the estimate instead of the plan. If the <code>Gather Streams<\/code> is what the optimizer refuses to pay for, it only has to believe that almost no rows will cross it. So I gave it a filter it judges extremely selective, and that removes nothing at runtime:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\ndeclare @impossiblevalue int = 0;\n\nSELECT * FROM dbo.Users WHERE reputation &gt;= @impossiblevalue\nOPTION (OPTIMIZE FOR (@impossiblevalue = 1000000));\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"909\" height=\"199\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-21.png\" alt=\"\" class=\"wp-image-46990\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-21.png 909w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-21-300x66.png 300w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-21-767x168.png 767w\" sizes=\"auto, (max-width: 909px) 100vw, 909px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Finally, some parallelism has been introduced!<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The statistics show nothing anywhere near a million reputation points, so the plan is compiled for an estimate of 45 rows (based on the density vector). At runtime <code>@impossiblevalue<\/code> is 0 and every one of the 299\u2019398 users comes back. The optimizer, fooled into seeing a nearly free <code>Gather Streams<\/code>, finally picks the parallel plan.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th><\/th><th>Scan count<\/th><th>Read-ahead reads<\/th><th>CPU<\/th><\/tr><\/thead><tbody><tr><td>Serial (optimizer choice)<\/td><td>1<\/td><td>7&#8217;401<\/td><td>1.016 s<\/td><\/tr><tr><td>Parallel (forced)<\/td><td>5<\/td><td>7&#8217;401<\/td><td>2.844 s<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">And let&#8217;s see the main wait statistics of both executions :<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Wait<\/th><th>Serial<\/th><th>Forced parallel<\/th><\/tr><\/thead><tbody><tr><td>PAGEIOLATCH_SH<\/td><td>41 ms<\/td><td>2&#8217;237 ms<\/td><\/tr><tr><td>CXPACKET<\/td><td>none<\/td><td>20\u2019935 ms (60\u2019181 waits)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><code>CXPACKET<\/code> is the price of the streams we created by introducing parallelism. 4 producer threads fill packets for a single consumer, which can only hand rows to SSMS as fast as SSMS accepts them. When the exchange buffers are full, the producers wait. The 21 seconds are summed across threads and the wide rows mean few rows per packet, hence the 60&#8217;000 waits.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>PAGEIOLATCH_SH<\/code> also grew, from 41 ms to 2&#8217;237 ms. Several threads competing for pages of the same table is a plausible explanation, but I have no real proof of it.<\/p>\n\n\n\n<h3 id=\"h-what-to-take-from-this\" class=\"wp-block-heading\">What to take from this<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For a query that reads the whole table and returns the whole table, most of the estimated cost is I\/O, and the optimizer <strong>never divides I\/O between threads<\/strong>. On <code>Users<\/code>, that left ~90 percent of the scan cost untouched by parallelism, and only the remaining CPU share, about 0.33, available to be split. Against that small saving, the parallel plan has to pay for funnelling every row through a single exchange, and on this table the exchange cost more than the plan could save. Row count does not change the outcome, since the I\/O, the CPU and the exchange all grow with it. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What makes the optimizer choose a parallel plan is the estimated number of rows crossing the exchange: the forced plan got there with an integer comparison that costs nothing, simply because the estimate dropped to 45 rows. What makes a parallel plan actually faster is something else, real CPU work per row to spread across threads, and few rows coming out at the end. The <code>LIKE<\/code> query has both, which is why it wins. The forced plan had neither, and it burned almost three times the CPU.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Why SQL Server keeps a full SELECT * serial: I\/O cost is never divided across threads. Forcing parallelism burned 3x the CPU.<\/p>\n","protected":false},"author":157,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":"","_members_access_role":[],"_members_access_error":""},"categories":[368,99],"tags":[4231,1743,51,1218],"type_dbi":[],"class_list":["post-46987","post","type-post","status-publish","format-standard","hentry","category-development-performance","category-sql-server","tag-clustered-index","tag-parallel-execution","tag-sql-server","tag-tuning"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v28.5 (Yoast SEO v28.5) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>SQL Server: why can&#039;t I read the full table in parallel??? - dbi Blog<\/title>\n<meta name=\"description\" content=\"Why SQL Server keeps a full SELECT * serial: I\/O cost is never divided across threads. Forcing parallelism burned 3x the CPU.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"SQL Server: why can&#039;t I read the full table in parallel???\" \/>\n<meta property=\"og:description\" content=\"Why SQL Server keeps a full SELECT * serial: I\/O cost is never divided across threads. Forcing parallelism burned 3x the CPU.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-21T16:56:45+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-21T17:51:43+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-22.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1159\" \/>\n\t<meta property=\"og:image:height\" content=\"294\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Louis Tochon\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Louis Tochon\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/sql-server-why-cant-i-read-the-full-table-in-parallel\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/sql-server-why-cant-i-read-the-full-table-in-parallel\\\/\"},\"author\":{\"name\":\"Louis Tochon\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/e4195b0cb120295b3407a502c23e75b6\"},\"headline\":\"SQL Server: why can&#8217;t I read the full table in parallel???\",\"datePublished\":\"2026-09-21T16:56:45+00:00\",\"dateModified\":\"2026-09-21T17:51:43+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/sql-server-why-cant-i-read-the-full-table-in-parallel\\\/\"},\"wordCount\":979,\"commentCount\":0,\"image\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/sql-server-why-cant-i-read-the-full-table-in-parallel\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2026\\\/09\\\/image-22-1024x260.png\",\"keywords\":[\"clustered index\",\"Parallel Execution\",\"SQL Server\",\"tuning\"],\"articleSection\":[\"Development &amp; Performance\",\"SQL Server\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/sql-server-why-cant-i-read-the-full-table-in-parallel\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/sql-server-why-cant-i-read-the-full-table-in-parallel\\\/\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/sql-server-why-cant-i-read-the-full-table-in-parallel\\\/\",\"name\":\"SQL Server: why can't I read the full table in parallel??? - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/sql-server-why-cant-i-read-the-full-table-in-parallel\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/sql-server-why-cant-i-read-the-full-table-in-parallel\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2026\\\/09\\\/image-22-1024x260.png\",\"datePublished\":\"2026-09-21T16:56:45+00:00\",\"dateModified\":\"2026-09-21T17:51:43+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/e4195b0cb120295b3407a502c23e75b6\"},\"description\":\"Why SQL Server keeps a full SELECT * serial: I\\\/O cost is never divided across threads. Forcing parallelism burned 3x the CPU.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/sql-server-why-cant-i-read-the-full-table-in-parallel\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/sql-server-why-cant-i-read-the-full-table-in-parallel\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/sql-server-why-cant-i-read-the-full-table-in-parallel\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2026\\\/09\\\/image-22.png\",\"contentUrl\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2026\\\/09\\\/image-22.png\",\"width\":1159,\"height\":294},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/sql-server-why-cant-i-read-the-full-table-in-parallel\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"SQL Server: why can&#8217;t I read the full table in parallel???\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/e4195b0cb120295b3407a502c23e75b6\",\"name\":\"Louis Tochon\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ce0ee48c64e763e6c4076e21c80729d15bc4493288aeb8695125c69082100e10?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ce0ee48c64e763e6c4076e21c80729d15bc4493288aeb8695125c69082100e10?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ce0ee48c64e763e6c4076e21c80729d15bc4493288aeb8695125c69082100e10?s=96&d=mm&r=g\",\"caption\":\"Louis Tochon\"},\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/author\\\/louistochon\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"SQL Server: why can't I read the full table in parallel??? - dbi Blog","description":"Why SQL Server keeps a full SELECT * serial: I\/O cost is never divided across threads. Forcing parallelism burned 3x the CPU.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/","og_locale":"en_US","og_type":"article","og_title":"SQL Server: why can't I read the full table in parallel???","og_description":"Why SQL Server keeps a full SELECT * serial: I\/O cost is never divided across threads. Forcing parallelism burned 3x the CPU.","og_url":"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/","og_site_name":"dbi Blog","article_published_time":"2026-09-21T16:56:45+00:00","article_modified_time":"2026-09-21T17:51:43+00:00","og_image":[{"width":1159,"height":294,"url":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-22.png","type":"image\/png"}],"author":"Louis Tochon","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Louis Tochon","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/"},"author":{"name":"Louis Tochon","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/e4195b0cb120295b3407a502c23e75b6"},"headline":"SQL Server: why can&#8217;t I read the full table in parallel???","datePublished":"2026-09-21T16:56:45+00:00","dateModified":"2026-09-21T17:51:43+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/"},"wordCount":979,"commentCount":0,"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-22-1024x260.png","keywords":["clustered index","Parallel Execution","SQL Server","tuning"],"articleSection":["Development &amp; Performance","SQL Server"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/","url":"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/","name":"SQL Server: why can't I read the full table in parallel??? - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/#primaryimage"},"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-22-1024x260.png","datePublished":"2026-09-21T16:56:45+00:00","dateModified":"2026-09-21T17:51:43+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/e4195b0cb120295b3407a502c23e75b6"},"description":"Why SQL Server keeps a full SELECT * serial: I\/O cost is never divided across threads. Forcing parallelism burned 3x the CPU.","breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/#primaryimage","url":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-22.png","contentUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/09\/image-22.png","width":1159,"height":294},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-why-cant-i-read-the-full-table-in-parallel\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"SQL Server: why can&#8217;t I read the full table in parallel???"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/e4195b0cb120295b3407a502c23e75b6","name":"Louis Tochon","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/ce0ee48c64e763e6c4076e21c80729d15bc4493288aeb8695125c69082100e10?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/ce0ee48c64e763e6c4076e21c80729d15bc4493288aeb8695125c69082100e10?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/ce0ee48c64e763e6c4076e21c80729d15bc4493288aeb8695125c69082100e10?s=96&d=mm&r=g","caption":"Louis Tochon"},"url":"https:\/\/www.dbi-services.com\/blog\/author\/louistochon\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/46987","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/157"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=46987"}],"version-history":[{"count":36,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/46987\/revisions"}],"predecessor-version":[{"id":47033,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/46987\/revisions\/47033"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=46987"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=46987"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=46987"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=46987"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}