{"id":3317,"date":"2020-05-17T17:59:57","date_gmt":"2020-05-17T17:59:57","guid":{"rendered":"https:\/\/nenadnoveljic.com\/blog\/?p=3317"},"modified":"2020-05-17T17:59:59","modified_gmt":"2020-05-17T17:59:59","slug":"suboptimal-sort-calculation","status":"publish","type":"post","link":"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/","title":{"rendered":"Suboptimal Sort Calculation"},"content":{"rendered":"<p>There is a substantial difference in how MS SQL Server and Oracle estimate the cost of a sort operation. The critical point isn&#8217;t in the algorithm itself. As we shall see, the problem exists rather on a much more basic level &#8211; in the inputs variables. On the one hand, Oracle relies on column statistics to produce accurate estimates. On the other hand, MS SQL Server uses data type size declared in the column definition. But this value is just the static maximum size that a column can store. The actual data size is, in fact, often much lower. Consequently, the estimates will be out of the ballpark in such cases. It goes without saying that this can have a detrimental effect on performance. I&#8217;ll be showing such a case and provide a workaround for affected queries.<\/p>\n<p>But first of all, let me demonstrate how both products calculate the sort cost. The versions I used are SQL Server 2019 and Oracle 19c.<\/p>\n<h1>Oracle<\/h1>\n<p>I&#8217;ll be using the following data model with Oracle:<\/p>\n<pre><code>create table t ( \n  c_type_size_<span style=\"color: blue;\">1<\/span>_length_1 varchar2(<span style=\"color: blue;\">1<\/span>),\n  c_type_size_<span style=\"color: blue;\">4000<\/span>_length_1 varchar2(<span style=\"color: blue;\">4000<\/span>),\n  c_type_size_<span style=\"color: blue;\">4000<\/span>_length_<span style=\"color: red;\">4000<\/span> varchar2(<span style=\"color: blue;\">4000<\/span>)\n);\n\ninsert into t \n  select 'A', 'A', LPAD('A',<span style=\"color: red;\">4000<\/span>,'A') from dual connect by level&lt;=1e4 ;\n  \ncommit ;\n\nexec dbms_stats.gather_table_stats(null,'T');<\/code><\/pre>\n<p>Basically, I created a table with three varchar2 columns. I inserted a single character into two columns with different max sizes: varchar2(1) and varchar2(4000). Finally, I inserted a long string into the varchar2(4000) column.<\/p>\n<p>With the following statements we can observe how the calculation changes over two dimensions. One is the data type size in the column definition. The other is the actual data size:<\/p>\n<pre><code>\nselect c_type_size_1_length_1 from t order by 1 ;\nselect c_type_size_4000_length_1 from t order by 1 ;\nselect c_type_size_4000_length_4000 from t order by 1 ;\n<\/code><\/pre>\n<p>Here&#8217;s, for example, the execution plan for the last statement:<\/p>\n<pre><code>SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR);\nselect c_type_size_4000_length_4000 from t order by 1\n\nPlan hash value: 961378228\n\n-----------------------------------------------------------------------------------\n| Id  | Operation          | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |\n-----------------------------------------------------------------------------------\n|   0 | SELECT STATEMENT   |      |       |       |       |  4037 (100)|          |\n|   1 |  SORT ORDER BY     |      | 10000 |    38M|    39M|  <span style=\"color: blue;\">4037<\/span>   (1)| 00:00:01 |\n|   2 |   TABLE ACCESS FULL| T    | 10000 |    38M|       |   <span style=\"color: blue;\">737<\/span>   (0)| 00:00:01 |\n-----------------------------------------------------------------------------------\n<\/code><\/pre>\n<p>The cost attributed to the sort operation also entails the cost of its child operation. Consequently, the contribution of the sort operation itself is 3300 (<span style=\"color: blue;\">4037<\/span>&#8211;<span style=\"color: blue;\">737)<\/span>.<\/p>\n<p>The table below shows the sort costs for all three cases.<\/p>\n\n<table id=\"tablepress-11\" class=\"tablepress tablepress-id-11\">\n<thead>\n<tr class=\"row-1\">\n\t<th class=\"column-1\">actual size, max size<\/th><th class=\"column-2\">cost<\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"row-striping row-hover\">\n<tr class=\"row-2\">\n\t<td class=\"column-1\">1, 1<\/td><td class=\"column-2\">1<\/td>\n<\/tr>\n<tr class=\"row-3\">\n\t<td class=\"column-1\"><span style=\"color:green\">1, 4000<\/span><\/td><td class=\"column-2\"><span style=\"color:green\">1<\/span><\/td>\n<\/tr>\n<tr class=\"row-4\">\n\t<td class=\"column-1\">4000, 4000<\/td><td class=\"column-2\">3300<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<!-- #tablepress-11 from cache -->\n<p>As you can see, the cost didn&#8217;t increase after storing a single character in the varchar2(4000) column. The optimizer ignored the data type max size and used the actual data size. This is correct, because the resource consumption depends on the actual result set size and not on the defined column limit.<\/p>\n<p>By the way, the following column statistics were used for estimating the actual data size:<\/p>\n<pre><code>col column_name format a30\nselect column_name,avg_col_len from dba_tab_columns  where owner='SYS' and table_name='T';\n\nCOLUMN_NAME                    AVG_COL_LEN\n------------------------------ -----------\nC_TYPE_SIZE_1_LENGTH_1                   2\nC_TYPE_SIZE_4000_LENGTH_1                2\nC_TYPE_SIZE_4000_LENGTH_4000          4001<\/code><\/pre>\n<h1>MS SQL Server<\/h1>\n<p>Unfortunately, MS SQL Server handles it the other way around. I&#8217;m using a similar data model to prove that:<\/p>\n<pre><code>create table t ( \n  c_type_size_1_length_1 nvarchar(1),\n  c_type_size_4000_length_1 nvarchar(4000),\n  c_type_size_4000_length_4000 nvarchar(4000)\n);\n\n\ninsert into t\nSELECT TOP (10000)\n  'A', 'A', right(replicate('A',4000) + 'A',4000) \n  FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2 \n  OPTION (MAXDOP 1);\n\nCREATE STATISTICS c_type_size_1_length_1 \n  ON t ( c_type_size_1_length_1 ) with fullscan ;\n  \nCREATE STATISTICS c_type_size_4000_length_1 \n  ON t ( c_type_size_4000_length_1 ) with fullscan ;\n\nCREATE STATISTICS c_type_size_4000_length_4000\n  ON t ( c_type_size_4000_length_4000 ) with fullscan ;\n\n\nselect c_type_size_1_length_1 from t order by 1 ;\n\nselect c_type_size_4000_length_1 from t order by 1 ;\n\nselect c_type_size_4000_length_4000 from t order by 1 ;<\/code><\/pre>\n<p>In the following execution plan the result set contains a single character that was retrieved from the nvarchar(4000) column c_type_size_4000_length_1:<\/p>\n<p><a href=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/sort_cost.png\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"209\" class=\"alignnone size-medium wp-image-3341\" alt=\"\" src=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/sort_cost-300x209.png\" srcset=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/sort_cost-300x209.png 300w, https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/sort_cost.png 650w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>According to the output above, the data size used for the cost calculation is 4011B, even though the effective length of stored information was 1.<\/p>\n<p>Curiously, the column statistics are accurate, but the optimizer didn&#8217;t use them at all:<\/p>\n<pre><code>Statistics for INDEX 'c_type_size_4000_length_1'.\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n\n                            Name                         Updated                            Rows                    Rows Sampled                           Steps                         Density              Average Key Length                    String Index\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n       c_type_size_4000_length_1             May 15 2020 11:04AM                           10000                           10000                               1                               0                               2                             YES                                                           10000                               0\n\n                     All Density                  <span style=\"color: blue;\">Average Length<\/span>                         Columns\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n                               1                               <span style=\"color: blue;\">2<\/span>       c_type_size_4000_length_1\n\n                 Histogram Steps\n                    RANGE_HI_KEY                      RANGE_ROWS                         EQ_ROWS             DISTINCT_RANGE_ROWS                  AVG_RANGE_ROWS\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n                               A                               0                           10000                               0                               1<\/code><\/pre>\n<p>Comparing the costs of sorting different columns also confirms that the data type size is used in the sort calculation cost:<\/p>\n\n<table id=\"tablepress-13\" class=\"tablepress tablepress-id-13\">\n<thead>\n<tr class=\"row-1\">\n\t<th class=\"column-1\">actual size, max size<\/th><th class=\"column-2\">cost<\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"row-striping row-hover\">\n<tr class=\"row-2\">\n\t<td class=\"column-1\">1, 1<\/td><td class=\"column-2\">0.30734<\/td>\n<\/tr>\n<tr class=\"row-3\">\n\t<td class=\"column-1\"><span style=\"color:red\">1, 4000<\/span><\/td><td class=\"column-2\"><span style=\"color:red\">56.34279<\/span><\/td>\n<\/tr>\n<tr class=\"row-4\">\n\t<td class=\"column-1\">4000, 4000<\/td><td class=\"column-2\">56.34279<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<!-- #tablepress-13 from cache -->\n<p>In other words, MS SQL Sever ignored the column statistics.<\/p>\n<p>As we shall see later, a misestimate in the sort cost calculation can cause a butterfly effect leading to performance disasters with more complex execution plans.<\/p>\n<h1>Case study<\/h1>\n<p>Below is the model of a recent production issue:<\/p>\n<pre><code>drop table t_big\n\ncreate table t_big( n1 integer, n2 integer )\n\ninsert into t_big\nSELECT TOP (100000)\n  1, CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id]))\n  FROM sys.all_objects s1 CROSS JOIN sys.all_objects AS s2\n  OPTION (MAXDOP 1);\n\ndrop table t_small\n\ncreate table t_small ( \n  n1 integer, \n  c_type_size_1_length_1  nvarchar(1), \n  c_type_size_4000_length_1  nvarchar(4000)\n)\n\ninsert into t_small values (1,'A','A')<\/code><\/pre>\n<p>Let&#8217;s consider the following query that joins two tables producing a large result set due to the large driving table. For reference, we&#8217;re first selecting the small column, that is nvarchar(1), from the small table.<\/p>\n<pre><code>select \n\tc_type_size_1_length_1\n  from t_big left outer join t_small on t_big.n1 = t_small.n1 \n  order by t_big.n2<\/code><\/pre>\n<p><a href=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/join_sort_short.png\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"55\" class=\"alignnone size-medium wp-image-3336\" alt=\"\" src=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/join_sort_short-300x55.png\" srcset=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/join_sort_short-300x55.png 300w, https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/join_sort_short-768x142.png 768w, https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/join_sort_short.png 889w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Expectedly, sort was applied to the hash join (HJ) output. The optimizer figured out correctly that this is an efficient plan, because the cost of sorting the result set containing 1 character column is low.<\/p>\n<p>But the execution plan changes for worse after selecting the nvarchar(4000) column, although the data is exactly the same (only the declared data size changed):<\/p>\n<pre><code>select \n\tc_type_size_4000_length_1\n  from t_big left outer join t_small on t_big.n1 = t_small.n1 \n  order by t_big.n2 ;<\/code><\/pre>\n<p><a href=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/join_sort_long.png\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"73\" class=\"alignnone size-medium wp-image-3339\" alt=\"\" src=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/join_sort_long-300x73.png\" srcset=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/join_sort_long-300x73.png 300w, https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/join_sort_long.png 672w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Simply put, because of the increased data type size (not the actual data, though!) the optimizer wrongly decided that sorting the whole result set at the end is too expensive. The large table was sorted before joining it with the small table by using nested loop (NL), instead. As a consequence, NL generated <span style=\"color: red;\">100&#8217;000<\/span> page visits on the small table:<\/p>\n<pre><code>Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.\nTable 't_big'. Scan count 3, logical reads 384, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.\nTable 't_small'. Scan count 1, logical reads <span style=\"color: red;\">100000<\/span>, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.<\/code><\/pre>\n<p>To quantify the magnitude of this damage, we&#8217;ll compare the execution statistics with those produced by the same query, but with HJ enforced:<\/p>\n<pre><code>select \n\tc_type_size_4000_length_1\n  from t_big left outer <span style=\"color: blue;\">hash join<\/span> t_small on t_big.n1 = t_small.n1 \n  order by t_big.n2<\/code><\/pre>\n<p>The small table was accessed only <span style=\"color: green;\">once<\/span> with HJ:<\/p>\n<pre><code>(100000 rows affected)\nTable 't_big'. Scan count 3, logical reads 384, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.\nTable 't_small'. Scan count 1, logical reads <span style=\"color: green;\">1<\/span>, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.\nTable 'Workfile'. Scan count 2, logical reads 280, physical reads 31, page server reads 0, read-ahead reads 249, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.\nTable 'Worktable'. Scan count 0, logical reads 0, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.\nTable 'Worktable'. Scan count 0, logical reads 0, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.<\/code><\/pre>\n<p><a href=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/hj_long.png\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"58\" class=\"alignnone size-medium wp-image-3338\" alt=\"\" src=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/hj_long-300x58.png\" srcset=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/hj_long-300x58.png 300w, https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/hj_long-768x149.png 768w, https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/hj_long.png 884w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>In conclusion, the sort cost overestimate caused an increase of logical reads by several orders of magnitude.<\/p>\n<h1>Anti-pattern<\/h1>\n<p>Based on the example above, we can generalize an anti-pattern to be found in the affected execution plans. Potentially troublesome queries can have a premature sort that feeds a NL, which, in turn, produces a logical read explosion.<\/p>\n<h1>Workaround<\/h1>\n<p>Is there a way to fix that (apart from obvious options of reducing the data type size to a bare minimum or eliminating unnecessary order by clauses)?<\/p>\n<p>You can try producing a better execution plan and enforce it in the query store. To do this, you can temporarily increase the CPU cost weight to make the sort more attractive to the optimizer. The sort cost, namely, consists chiefly of the IO cost.<\/p>\n<p>First, check the actual weights:<\/p>\n<pre><code>DBCC    TRACEON (3604);\nDBCC    SHOWWEIGHTS;\n\nDBCC Opt Weights CPU: 1.000000  IO: 1.000000 SPID 54<\/code><\/pre>\n<p>Second, increase temporarily the CPU weight and clear the proccache:<\/p>\n<pre><code>DBCC SETCPUWEIGHT(100)\nDBCC FREEPROCCACHE<\/code><\/pre>\n<p>(Keep increasing the CPU weight until you get a better plan.)<\/p>\n<p>Third, restore the old weight value once you got a good plan:<\/p>\n<pre><code>DBCC SETCPUWEIGHT(1)<\/code><\/pre>\n<p>Finally, fix the new plan in the query store.<\/p>\n<p>Below we can see such a plan that I enforced in the query store after applying the described procedure.<\/p>\n<p><a href=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/captured_plan.png\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"64\" class=\"alignnone size-medium wp-image-3337\" alt=\"\" src=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/captured_plan-300x64.png\" srcset=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/captured_plan-300x64.png 300w, https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/captured_plan-1024x218.png 1024w, https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/captured_plan-768x163.png 768w, https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/captured_plan.png 1078w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<h1>Summary<\/h1>\n<p>In summary, unlike Oracle, MS SQL Server uses the data type length from the column definition instead of column statistics for estimating sort operation cost. Consequently, the sort cost will be massively overestimated for underused columns. This will inevitably lead to bad plans. There isn&#8217;t a good solution for this. But in some cases, it is feasible to temporarily increase CPU weight to obtain a better plan that can then be pinned in the query store.<\/p>\n<h1>Related blog posts<\/h1>\n<p>In this blog post I didn&#8217;t cover any details of the sort calculation. I&#8217;ve been focusing on a very specific inefficiency in MS SQL Server, instead, and comparing it to Oracle.<\/p>\n<p>But I was already dealing in detail with the sort cost calculation in Oracle in the following articles:<\/p>\n<ul>\n<li><a href=\"https:\/\/nenadnoveljic.com\/blog\/io-sort-cost-calculation\/\">IO Sort Calculation<\/a> : researching Oracle C functions participating in the calculation, formulae, PL\/SQL sort cost calculator<\/li>\n<li><a href=\"https:\/\/nenadnoveljic.com\/blog\/io-sort-cost-calculation-2\/\">IO Sort Calculation (2)<\/a>: expanding on math underpinning the calculation<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Beware of the suboptimal sort cost calculation in SQL Server. Comparison with Oracle included. <a href=\"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/\" class=\"more-link\">Continue Reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[21,11,5,32,17],"tags":[],"class_list":["post-3317","post","type-post","status-publish","format-standard","hentry","category-comparison-oracle-sql-server","category-cost-based-optimizer","category-oracle","category-sort","category-sql-server"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Suboptimal Sort Calculation - All-round Database Topics<\/title>\n<meta name=\"description\" content=\"Beware of the suboptimal sort cost calculation in SQL Server. Comparison with Oracle included.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Suboptimal Sort Calculation - All-round Database Topics\" \/>\n<meta property=\"og:description\" content=\"Beware of the suboptimal sort cost calculation in SQL Server. Comparison with Oracle included.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/\" \/>\n<meta property=\"og:site_name\" content=\"All-round Database Topics\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-17T17:59:57+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-05-17T17:59:59+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/sort_cost-300x209.png\" \/>\n<meta name=\"author\" content=\"Nenad Noveljic\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@NenadNoveljic\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Nenad Noveljic\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/suboptimal-sort-calculation\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/suboptimal-sort-calculation\\\/\"},\"author\":{\"name\":\"Nenad Noveljic\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#\\\/schema\\\/person\\\/51458d9dd86dbbdd19f5add451d44efa\"},\"headline\":\"Suboptimal Sort Calculation\",\"datePublished\":\"2020-05-17T17:59:57+00:00\",\"dateModified\":\"2020-05-17T17:59:59+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/suboptimal-sort-calculation\\\/\"},\"wordCount\":1055,\"commentCount\":0,\"image\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/suboptimal-sort-calculation\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/wp-content\\\/uploads\\\/2020\\\/05\\\/sort_cost-300x209.png\",\"articleSection\":[\"Comparison Oracle-SQL Server\",\"cost based optimizer\",\"Oracle\",\"sort\",\"SQL Server\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/suboptimal-sort-calculation\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/suboptimal-sort-calculation\\\/\",\"url\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/suboptimal-sort-calculation\\\/\",\"name\":\"Suboptimal Sort Calculation - All-round Database Topics\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/suboptimal-sort-calculation\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/suboptimal-sort-calculation\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/wp-content\\\/uploads\\\/2020\\\/05\\\/sort_cost-300x209.png\",\"datePublished\":\"2020-05-17T17:59:57+00:00\",\"dateModified\":\"2020-05-17T17:59:59+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#\\\/schema\\\/person\\\/51458d9dd86dbbdd19f5add451d44efa\"},\"description\":\"Beware of the suboptimal sort cost calculation in SQL Server. Comparison with Oracle included.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/suboptimal-sort-calculation\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/suboptimal-sort-calculation\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/suboptimal-sort-calculation\\\/#primaryimage\",\"url\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/wp-content\\\/uploads\\\/2020\\\/05\\\/sort_cost.png\",\"contentUrl\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/wp-content\\\/uploads\\\/2020\\\/05\\\/sort_cost.png\",\"width\":650,\"height\":453},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/suboptimal-sort-calculation\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Suboptimal Sort Calculation\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/\",\"name\":\"All-round Database Topics\",\"description\":\"Nenad Noveljic\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#\\\/schema\\\/person\\\/51458d9dd86dbbdd19f5add451d44efa\",\"name\":\"Nenad Noveljic\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/a97b796613ea48ec8a7b79c8ffe1c685dcffc920c68121f6238d5caab5070670?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/a97b796613ea48ec8a7b79c8ffe1c685dcffc920c68121f6238d5caab5070670?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/a97b796613ea48ec8a7b79c8ffe1c685dcffc920c68121f6238d5caab5070670?s=96&d=mm&r=g\",\"caption\":\"Nenad Noveljic\"},\"sameAs\":[\"nenad-noveljic-9b746a6\",\"https:\\\/\\\/x.com\\\/NenadNoveljic\"],\"url\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/author\\\/nenad\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Suboptimal Sort Calculation - All-round Database Topics","description":"Beware of the suboptimal sort cost calculation in SQL Server. Comparison with Oracle included.","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:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/","og_locale":"en_US","og_type":"article","og_title":"Suboptimal Sort Calculation - All-round Database Topics","og_description":"Beware of the suboptimal sort cost calculation in SQL Server. Comparison with Oracle included.","og_url":"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/","og_site_name":"All-round Database Topics","article_published_time":"2020-05-17T17:59:57+00:00","article_modified_time":"2020-05-17T17:59:59+00:00","og_image":[{"url":"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/sort_cost-300x209.png","type":"","width":"","height":""}],"author":"Nenad Noveljic","twitter_card":"summary_large_image","twitter_creator":"@NenadNoveljic","twitter_misc":{"Written by":"Nenad Noveljic","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/#article","isPartOf":{"@id":"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/"},"author":{"name":"Nenad Noveljic","@id":"https:\/\/nenadnoveljic.com\/blog\/#\/schema\/person\/51458d9dd86dbbdd19f5add451d44efa"},"headline":"Suboptimal Sort Calculation","datePublished":"2020-05-17T17:59:57+00:00","dateModified":"2020-05-17T17:59:59+00:00","mainEntityOfPage":{"@id":"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/"},"wordCount":1055,"commentCount":0,"image":{"@id":"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/#primaryimage"},"thumbnailUrl":"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/sort_cost-300x209.png","articleSection":["Comparison Oracle-SQL Server","cost based optimizer","Oracle","sort","SQL Server"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/","url":"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/","name":"Suboptimal Sort Calculation - All-round Database Topics","isPartOf":{"@id":"https:\/\/nenadnoveljic.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/#primaryimage"},"image":{"@id":"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/#primaryimage"},"thumbnailUrl":"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/sort_cost-300x209.png","datePublished":"2020-05-17T17:59:57+00:00","dateModified":"2020-05-17T17:59:59+00:00","author":{"@id":"https:\/\/nenadnoveljic.com\/blog\/#\/schema\/person\/51458d9dd86dbbdd19f5add451d44efa"},"description":"Beware of the suboptimal sort cost calculation in SQL Server. Comparison with Oracle included.","breadcrumb":{"@id":"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/#primaryimage","url":"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/sort_cost.png","contentUrl":"https:\/\/nenadnoveljic.com\/blog\/wp-content\/uploads\/2020\/05\/sort_cost.png","width":650,"height":453},{"@type":"BreadcrumbList","@id":"https:\/\/nenadnoveljic.com\/blog\/suboptimal-sort-calculation\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/nenadnoveljic.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Suboptimal Sort Calculation"}]},{"@type":"WebSite","@id":"https:\/\/nenadnoveljic.com\/blog\/#website","url":"https:\/\/nenadnoveljic.com\/blog\/","name":"All-round Database Topics","description":"Nenad Noveljic","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/nenadnoveljic.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/nenadnoveljic.com\/blog\/#\/schema\/person\/51458d9dd86dbbdd19f5add451d44efa","name":"Nenad Noveljic","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/a97b796613ea48ec8a7b79c8ffe1c685dcffc920c68121f6238d5caab5070670?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/a97b796613ea48ec8a7b79c8ffe1c685dcffc920c68121f6238d5caab5070670?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/a97b796613ea48ec8a7b79c8ffe1c685dcffc920c68121f6238d5caab5070670?s=96&d=mm&r=g","caption":"Nenad Noveljic"},"sameAs":["nenad-noveljic-9b746a6","https:\/\/x.com\/NenadNoveljic"],"url":"https:\/\/nenadnoveljic.com\/blog\/author\/nenad\/"}]}},"_links":{"self":[{"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts\/3317","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/comments?post=3317"}],"version-history":[{"count":1,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts\/3317\/revisions"}],"predecessor-version":[{"id":3365,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts\/3317\/revisions\/3365"}],"wp:attachment":[{"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/media?parent=3317"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/categories?post=3317"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/tags?post=3317"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}