{"id":432,"date":"2008-01-22T20:16:50","date_gmt":"2008-01-22T20:16:50","guid":{"rendered":"\/blogs\/conor\/post\/INteresting.aspx"},"modified":"2008-01-22T20:16:50","modified_gmt":"2008-01-22T20:16:50","slug":"interesting","status":"publish","type":"post","link":"https:\/\/www.sqlskills.com\/blogs\/conor\/interesting\/","title":{"rendered":"INteresting&#8230;"},"content":{"rendered":"<p>In this post, I&#8217;ll go over a few things about IN plans in the SQL Server Query Optimizer.&nbsp; Currently I&#8217;m using the SQL Server 2008 November CTP, but this behavior is still valid on SQL 2005.<\/p>\n<p>I&#8217;ll be using the following script for my discussion, and you can try this on your own.<\/p>\n<p>create database in1<br \/>use in1<\/p>\n<p>create table t1(col1 int identity, col2 int default rand()*100000, col3 binary(2000))<\/p>\n<p>declare @i int<br \/>set @i=0<br \/>while @i &lt; 10000<br \/>begin<br \/>insert into t1 default values<br \/>set @i=@i+1<br \/>end<\/p>\n<p>create table t2(col1 int identity, col2 binary(200))<\/p>\n<p>&#8212; plan 1<br \/>select * from t1 where col2 in (1)<\/p>\n<p>&#8212; plan 2<br \/>select * from t1 where col2 in (1,2,3,4,5,6,7,8,9,10)<\/p>\n<p>&#8212; plan 3<br \/>select * from t1 where col2 in (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)<\/p>\n<p>&#8212; plan 4<br \/>select * from t1 inner join t2 on t1.col1=t2.col1<br \/>where t1.col2 in (<br \/>1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,<br \/>51,52,53,54,55,56,57,58,59,60,61,62,63,64)<\/p>\n<p>&#8212; plan 5<br \/>select * from t1 inner join t2 on t1.col1=t2.col1<br \/>where t1.col2 in (<br \/>1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,<br \/>51,52,53,54,55,56,57,58,59,60,61,62,63,64,65)<\/p>\n<p>So, we have a database with 2 tables, and I created a bunch of random data in a column so that we can play with IN plans.<\/p>\n<p>ok, plan 1 is &#8220;easy&#8221;.&nbsp; I use IN with a single operator.&nbsp; This happens to turn into a simple plan that looks like this (using set showplan_text to view):<\/p>\n<p>&nbsp; |&#8211;Table Scan(OBJECT:([in1].[dbo].[t1]),WHERE:([in1].[dbo].[t1].[col2]=CONVERT_IMPLICIT(int,[@1],0)))<\/p>\n<p>Hrm.&nbsp; hey, the where clause is in the table scan?&nbsp; no separate operator?&nbsp; It&#8217;s a physical optimization that I&#8217;ll cover in another post (I may have covered this in my previous blog posts &#8211; I&#8217;ll go check), and it&#8217;s called &#8220;pushing non-SARG predicates&#8221; in SQL Server.<\/p>\n<p>Let&#8217;s compare with the plan for plan 2:<br \/>&nbsp; |&#8211;Table Scan(OBJECT:([in1].[dbo].[t1]), WHERE:([in1].[dbo].[t1].[col2]=(1) OR [in1].[dbo].[t1].[col2]=(2) OR [in1].[dbo].[t1].[col2]=(3) OR [in1].[dbo].[t1].[col2]=(4) OR [in1].[dbo].[t1].[col2]=(5) OR [in1].[dbo].[t1].[col2]=(6) OR [in1].[dbo].[t1].[col2]=(7) OR [in1].[dbo].[t1].[col2]=(8) OR [in1].[dbo].[t1].[col2]=(9) OR [in1].[dbo].[t1].[col2]=(10)))<\/p>\n<p>Same plan shape, just more conditions.<\/p>\n<p>I wonder if this goes on forever?&nbsp; Well, plan 3 looks different:<\/p>\n<p>&nbsp; |&#8211;Filter(WHERE:([in1].[dbo].[t1].[col2]=(1) OR [in1].[dbo].[t1].[col2]=(2) OR [in1].[dbo].[t1].[col2]=(3) OR [in1].[dbo].[t1].[col2]=(4) OR [in1].[dbo].[t1].[col2]=(5) OR [in1].[dbo].[t1].[col2]=(6) OR [in1].[dbo].[t1].[col2]=(7) OR [in1].[dbo].[t1].[col2]=(8) OR [in1].[dbo].[t1].[col2]=(9) OR [in1].[dbo].[t1].[col2]=(10) OR [in1].[dbo].[t1].[col2]=(11) OR [in1].[dbo].[t1].[col2]=(12) OR [in1].[dbo].[t1].[col2]=(13) OR [in1].[dbo].[t1].[col2]=(14) OR [in1].[dbo].[t1].[col2]=(15) OR [in1].[dbo].[t1].[col2]=(16)))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&#8211;Table Scan(OBJECT:([in1].[dbo].[t1]))<\/p>\n<p>Now the filter is split out into another query operator.&nbsp; (It starts happening with 16 predicates)<\/p>\n<p>OK, these 3 plans have been simple query plans.&nbsp; In fact, you can do &#8220;set showplan_xml on&#8221; and run the query and learn something about how much optimization was done on them:<\/p>\n<p>&lt;ShowPlanXML xmlns=&#8221;http:\/\/schemas.microsoft.com\/sqlserver\/2004\/07\/showplan&#8221; Version=&#8221;1.0&#8243; Build=&#8221;10.0.1075.23&#8243;&gt;<br \/>&nbsp; &lt;BatchSequence&gt;<br \/>&nbsp;&nbsp;&nbsp; &lt;Batch&gt;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Statements&gt;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;StmtSimple StatementText=&#8221;select * from t1 where col2 in (1)&#8221; StatementId=&#8221;1&#8243; StatementCompId=&#8221;1&#8243; StatementType=&#8221;SELECT&#8221; StatementSubTreeCost=&#8221;2.48687&#8243; StatementEstRows=&#8221;1&#8243; StatementOptmLevel=&#8221;<b>TRIVIAL<\/b>&#8221; ParameterizedText=&#8221;(@1 tinyint)SELECT * FROM [t1] WHERE [col2]=@1&#8243;&gt;<\/p>\n<p>The end-to-end design of the optimizer is beyond the scope of this post, but there are various stages of optimization and queries can &#8220;quit early&#8221; if they find a &#8220;good enough&#8221; plan.&nbsp; In this case, there aren&#8217;t actually any real cost-based decisions to make about which plan to run, so these plans are called &#8220;trivial&#8221;.<\/p>\n<p>Once you start adding joins into the mix, there are join orders to consider, and those are cost-based.&nbsp; You can see that the optimization level for plan 4 differs:<br \/>&lt;StmtSimple StatementText=&#8221;select * from t1 inner join t2 on t1.col1=t2.col1&amp;#xD;&amp;#xA;where t1.col2 in (&amp;#xD;&amp;#xA;1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,&amp;#xD;&amp;#xA;51,52,53,54,55,56,57,58,59,60,61,62,63,64)&#8221; StatementId=&#8221;1&#8243; StatementCompId=&#8221;1&#8243; StatementType=&#8221;SELECT&#8221; StatementSubTreeCost=&#8221;2.70289&#8243; StatementEstRows=&#8221;1&#8243; StatementOptmLevel=&#8221;<b>FULL<\/b>&#8220;&gt;<\/p>\n<p>One would infer that FULL &gt; TRIVIAL ;).<\/p>\n<p>Plan 4:<br \/>&nbsp; |&#8211;Hash Match(Inner Join, HASH:([in1].[dbo].[t2].[col1])=([in1].[dbo].[t1].[col1]))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&#8211;Table Scan(OBJECT:([in1].[dbo].[t2]))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&#8211;Filter(WHERE:([in1].[dbo].[t1].[col2]=(1) OR [in1].[dbo].[t1].[col2]=(2) OR [in1].[dbo].[t1].[col2]=(3) OR [in1].[dbo].[t1].[col2]=(4) OR [in1].[dbo].[t1].[col2]=(5) OR [in1].[dbo].[t1].[col2]=(6) OR [in1].[dbo].[t1].[col2]=(7) OR [in1].[dbo].[t1].[col2]=(8) OR [in1].[dbo].[t1].[col2]=(9) OR [in1].[dbo].[t1].[col2]=(10) OR [in1].[dbo].[t1].[col2]=(11) OR [in1].[dbo].[t1].[col2]=(12) OR [in1].[dbo].[t1].[col2]=(13) OR [in1].[dbo].[t1].[col2]=(14) OR [in1].[dbo].[t1].[col2]=(15) OR [in1].[dbo].[t1].[col2]=(16) OR [in1].[dbo].[t1].[col2]=(17) OR [in1].[dbo].[t1].[col2]=(18) OR [in1].[dbo].[t1].[col2]=(19) OR [in1].[dbo].[t1].[col2]=(20) OR [in1].[dbo].[t1].[col2]=(21) OR [in1].[dbo].[t1].[col2]=(22) OR [in1].[dbo].[t1].[col2]=(23) OR [in1].[dbo].[t1].[col2]=(24) OR [in1].[dbo].[t1].[col2]=(25) OR [in1].[dbo].[t1].[col2]=(26) OR [in1].[dbo].[t1].[col2]=(27) OR [in1].[dbo].[t1].[col2]=(28) OR [in1].[dbo].[t1].[col2]=(29) OR [in1].[dbo].[t1].[col2]=(30) OR [in1].[dbo].[t1].[col2]=(31) OR [in1].[dbo].[t1].[col2]=(32) OR [in1].[dbo].[t1].[col2]=(33) OR [in1].[dbo].[t1].[col2]=(34) OR [in1].[dbo].[t1].[col2]=(35) OR [in1].[dbo].[t1].[col2]=(36) OR [in1].[dbo].[t1].[col2]=(37) OR [in1].[dbo].[t1].[col2]=(38) OR [in1].[dbo].[t1].[col2]=(39) OR [in1].[dbo].[t1].[col2]=(40) OR [in1].[dbo].[t1].[col2]=(41) OR [in1].[dbo].[t1].[col2]=(42) OR [in1].[dbo].[t1].[col2]=(43) OR [in1].[dbo].[t1].[col2]=(44) OR [in1].[dbo].[t1].[col2]=(45) OR [in1].[dbo].[t1].[col2]=(46) OR [in1].[dbo].[t1].[col2]=(47) OR [in1].[dbo].[t1].[col2]=(48) OR [in1].[dbo].[t1].[col2]=(49) OR [in1].[dbo].[t1].[col2]=(50) OR [in1].[dbo].[t1].[col2]=(51) OR [in1].[dbo].[t1].[col2]=(52) OR [in1].[dbo].[t1].[col2]=(53) OR [in1].[dbo].[t1].[col2]=(54) OR [in1].[dbo].[t1].[col2]=(55) OR [in1].[dbo].[t1].[col2]=(56) OR [in1].[dbo].[t1].[col2]=(57) OR [in1].[dbo].[t1].[col2]=(58) OR [in1].[dbo].[t1].[col2]=(59) OR [in1].[dbo].[t1].[col2]=(60) OR [in1].[dbo].[t1].[col2]=(61) OR [in1].[dbo].[t1].[col2]=(62) OR [in1].[dbo].[t1].[col2]=(63) OR [in1].[dbo].[t1].[col2]=(64)))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&#8211;Table Scan(OBJECT:([in1].[dbo].[t1]))<\/p>\n<p>ok, this looks like an extension of what we saw in plan 3 &#8211; a filter operator above a table scan, followed by a join.<\/p>\n<p>Query 5 is only trivially different than 4 &#8211; 65 conditions instead of 64:<\/p>\n<p>&nbsp; |&#8211;Nested Loops(Left Semi Join, OUTER REFERENCES:([in1].[dbo].[t1].[col2]))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&#8211;Hash Match(Inner Join, HASH:([in1].[dbo].[t2].[col1])=([in1].[dbo].[t1].[col1]))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; |&#8211;Table Scan(OBJECT:([in1].[dbo].[t2]))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; |&#8211;Table Scan(OBJECT:([in1].[dbo].[t1]))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&#8211;Filter(WHERE:([in1].[dbo].[t1].[col2]=[Expr1008]))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&#8211;Constant Scan( VALUES:(((1)),((2)),((3)),((4)),((5)),((6)),((7)),((8)),((9)),((10)),((11)),((12)),((13)),((14)),((15)),((16)),((17)),((18)),((19)),((20)),((21)),((22)),((23)),((24)),((25)),((26)),((27)),((28)),((29)),((30)),((31)),((32)),((33)),((34)),((35)),((36)),((37)),((38)),((39)),((40)),((41)),((42)),((43)),((44)),((45)),((46)),((47)),((48)),((49)),((50)),((51)),((52)),((53)),((54)),((55)),((56)),((57)),((58)),((59)),((60)),((61)),((62)),((63)),((64)),((65))))<\/p>\n<p>Hey, what&#8217;s this?&nbsp; A Semi Join?&nbsp; Well, this is a join where rows from one side are joined with another table (in this case, an in-memory table) and only qualifying rows from the original table are kept.&nbsp; To make this work, you can&#8217;t return any columns from the &#8220;other side&#8221;, and you have to make sure you don&#8217;t have more than one match on the constant table.&nbsp; So, you need to remove duplicates.&nbsp; Try adding another &#8216;1&#8217; into the IN list and then look at the plan &#8211; it removes them.<\/p>\n<p>Why are there different plans at these points?&nbsp; Well, while I can&#8217;t speak for the development team, as I&#8217;m not on it anymore, but I will say that often these are added as an attempt to deal with poor performance or some very common queries that are seen all the time (perhaps from a large ISV).&nbsp; There&#8217;s obviously not a ton of magic to why 16 and 64 are picked for the magic numbers, and I&#8217;m sure if we hunted we could find some cases where the transition between plans was not perfect.&nbsp; Often changing the numbers, even if they aren&#8217;t quite perfect, will just cause instability elsewhere in terms of plan quality so they are left to try to avoid pain to customers.&nbsp; I&#8217;m hopeful that you can use this post to start to do the same kind of reasoning yourself.&nbsp; While I have a pretty good idea of where the plans will change, I&#8217;m not revealing anything you can&#8217;t see with some trial and error on your own.&nbsp; I actually had forgotten the 64 number, as I think it changed at one point &#8211; so, I had to do figure it out again ;).<\/p>\n<p>OK, this covers the basic forms of plans with INs that are available in SQL Server.&nbsp; I plan to work on the plan cache next, including forced parameterization.<\/p>\n<p>Thanks,<\/p>\n<p>Conor<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post, I&#8217;ll go over a few things about IN plans in the SQL Server Query Optimizer.&nbsp; Currently I&#8217;m using the SQL Server 2008 November CTP, but this behavior is still valid on SQL 2005. I&#8217;ll be using the following script for my discussion, and you can try this on your own. create database [&hellip;]<\/p>\n","protected":false},"author":6,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-432","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v21.9.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>INteresting... - Conor Cunningham<\/title>\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.sqlskills.com\/blogs\/conor\/interesting\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"INteresting... - Conor Cunningham\" \/>\n<meta property=\"og:description\" content=\"In this post, I&#8217;ll go over a few things about IN plans in the SQL Server Query Optimizer.&nbsp; Currently I&#8217;m using the SQL Server 2008 November CTP, but this behavior is still valid on SQL 2005. I&#8217;ll be using the following script for my discussion, and you can try this on your own. create database [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.sqlskills.com\/blogs\/conor\/interesting\/\" \/>\n<meta property=\"og:site_name\" content=\"Conor Cunningham\" \/>\n<meta property=\"article:published_time\" content=\"2008-01-22T20:16:50+00:00\" \/>\n<meta name=\"author\" content=\"Conor Cunningham\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Conor Cunningham\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/interesting\/\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/interesting\/\",\"name\":\"INteresting... - Conor Cunningham\",\"isPartOf\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#website\"},\"datePublished\":\"2008-01-22T20:16:50+00:00\",\"dateModified\":\"2008-01-22T20:16:50+00:00\",\"author\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/f9106e03423de6b5157295891b8c3ae3\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/interesting\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.sqlskills.com\/blogs\/conor\/interesting\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/interesting\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"INteresting&#8230;\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#website\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/\",\"name\":\"Conor Cunningham\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/f9106e03423de6b5157295891b8c3ae3\",\"name\":\"Conor Cunningham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d9c37eff231ec89c1b244347d966860875eea8b55b366911d2694e8cd9913e57?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d9c37eff231ec89c1b244347d966860875eea8b55b366911d2694e8cd9913e57?s=96&d=mm&r=g\",\"caption\":\"Conor Cunningham\"},\"url\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/author\/conor\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"INteresting... - Conor Cunningham","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.sqlskills.com\/blogs\/conor\/interesting\/","og_locale":"en_US","og_type":"article","og_title":"INteresting... - Conor Cunningham","og_description":"In this post, I&#8217;ll go over a few things about IN plans in the SQL Server Query Optimizer.&nbsp; Currently I&#8217;m using the SQL Server 2008 November CTP, but this behavior is still valid on SQL 2005. I&#8217;ll be using the following script for my discussion, and you can try this on your own. create database [&hellip;]","og_url":"https:\/\/www.sqlskills.com\/blogs\/conor\/interesting\/","og_site_name":"Conor Cunningham","article_published_time":"2008-01-22T20:16:50+00:00","author":"Conor Cunningham","twitter_misc":{"Written by":"Conor Cunningham","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/interesting\/","url":"https:\/\/www.sqlskills.com\/blogs\/conor\/interesting\/","name":"INteresting... - Conor Cunningham","isPartOf":{"@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#website"},"datePublished":"2008-01-22T20:16:50+00:00","dateModified":"2008-01-22T20:16:50+00:00","author":{"@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/f9106e03423de6b5157295891b8c3ae3"},"breadcrumb":{"@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/interesting\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.sqlskills.com\/blogs\/conor\/interesting\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/interesting\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.sqlskills.com\/blogs\/conor\/"},{"@type":"ListItem","position":2,"name":"INteresting&#8230;"}]},{"@type":"WebSite","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#website","url":"https:\/\/www.sqlskills.com\/blogs\/conor\/","name":"Conor Cunningham","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.sqlskills.com\/blogs\/conor\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/f9106e03423de6b5157295891b8c3ae3","name":"Conor Cunningham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d9c37eff231ec89c1b244347d966860875eea8b55b366911d2694e8cd9913e57?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d9c37eff231ec89c1b244347d966860875eea8b55b366911d2694e8cd9913e57?s=96&d=mm&r=g","caption":"Conor Cunningham"},"url":"https:\/\/www.sqlskills.com\/blogs\/conor\/author\/conor\/"}]}},"_links":{"self":[{"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/posts\/432","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/comments?post=432"}],"version-history":[{"count":0,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/posts\/432\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/media?parent=432"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/categories?post=432"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/tags?post=432"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}