{"id":3812,"date":"2021-06-29T16:47:42","date_gmt":"2021-06-29T16:47:42","guid":{"rendered":"https:\/\/nenadnoveljic.com\/blog\/?p=3812"},"modified":"2021-06-29T16:49:09","modified_gmt":"2021-06-29T16:49:09","slug":"anti-join-with-range-predicate","status":"publish","type":"post","link":"https:\/\/nenadnoveljic.com\/blog\/anti-join-with-range-predicate\/","title":{"rendered":"Anti Join with Range Predicate"},"content":{"rendered":"<p>We hit a performance problem which is a consequence of anti join on a range predicate.<\/p>\n<p>The problem arose in the Avaloq banking application; particulary, in the interface between backend and frontend. It went something along the lines of &#8220;a huge backlog of documents that are being transfered between two subsystems&#8221;.<\/p>\n<p>Why a blog post for that?<\/p>\n<p>First, I was curious about a very unusual execution plan. Second, I&#8217;m highlighting some options for improving the application process.<\/p>\n<p>The query in focus is as follows:<\/p>\n<pre><code>SELECT \/*+ task_atrx_exp_sync_mgr *\/ MAX(<span style=\"color:red\">ATRX_SEQ_NR<\/span>) \n  FROM ( \n    SELECT \/*+ INDEX_DESC(AX (ATRX_SEQ_NR)) *\/ AX.ATRX_SEQ_NR \n\t  FROM <span style=\"color:red\">ATRX AX<\/span> WHERE <span style=\"color:red\">AX.ATRX_SEQ_NR &lt;= :B2<\/span> AND <span style=\"color:red\">AX.ATRX_SEQ_NR &gt;= :B1<\/span> AND \n\t    NOT EXISTS \n         ( SELECT NULL \n\t\t     FROM <span style=\"color:blue\">OBJ_CONT_INVDT CI<\/span>\n\t\t\t WHERE <span style=\"color:blue\">AX.ATRX_SEQ_NR<\/span> BETWEEN <span style=\"color:blue\">CI.FROM_ATRX_SEQ_NR AND CI.TO_ATRX_SEQ_NR<\/span> ) \n\t  ORDER BY AX.ATRX_SEQ_NR DESC ) \n\t  WHERE ROWNUM &lt;= 1 ;<\/code><\/pre>\n<p>The query above was permanently executed. Based on the naming convention and the problem description, I assumed that this query was determining the next document to process. Notice that this query doesn&#8217;t do any &#8220;real&#8221; work, rather, it just determines the next document to process. But the execution time had kept increasing until it finally reached ~600s, although such queries normally take miliseconds to complete.<\/p>\n<p>I started with a semantic explanation of the query. It returns the highest ATRX.ATRX_SEQ_NR within the boundaries defined by the bind variables :B2 and :B1. At the same time, <span style=\"color:red\">ATRX.ATRX_SEQ_NR<\/span> doesn&#8217;t fall in the interval defined by the <span style=\"color:blue\">OBJ_CONT_INVDT.FROM_ATRX_SEQ_NR<\/span> and <span style=\"color:blue\">OBJ_CONT_INVDT.TO_ATRX_SEQ_NR<\/span>.<\/p>\n<p>The SQL Plan Monitor and the predicate section revealed immediately where the time goes:<\/p>\n<pre><code>SQL Plan Monitoring Details (Plan Hash Value=320913352)\n=============================================================================================================================================================================\n| Id   |             Operation              |        Name        |  Rows   | Cost |   Time    | Start  | Execs |   Rows   | Read | Read  | Mem | Activity | Activity Detail |\n|      |                                    |                    | (Estim) |      | Active(s) | Active |       | (Actual) | Reqs | Bytes |     |   (%)    |   (# samples)   |\n=============================================================================================================================================================================\n|    0 | SELECT STATEMENT                   |                    |         |      |           |        |     1 |          |      |       |   . |          |                 |\n|    1 |   SORT AGGREGATE                   |                    |       1 |      |           |        |     1 |          |      |       |   . |          |                 |\n|    2 |    COUNT STOPKEY                   |                    |         |      |           |        |     1 |          |      |       |   . |          |                 |\n|    3 |     VIEW                           |                    |    6485 | 3148 |           |        |     1 |          |      |       |   . |          |                 |\n|    4 |      FILTER                        |                    |         |      |           |        |     1 |          |      |       |   . |          |                 |\n| -&gt; 5 |       MERGE JOIN ANTI              |                    |    6485 | 3145 |       605 |     +7 |     1 |        0 |      |       |   . |          |                 |\n| -&gt; 6 |        INDEX RANGE SCAN DESCENDING | <span style=\"color:red\">ATRX#P<\/span>             |    649K |  815 |       605 |     +7 |     1 |     <span style=\"color:red\">343K<\/span> |  133 |   1MB |   . |          |                 |\n| -&gt; 7 |        FILTER                      |                    |         |      |       607 |     +5 |  <span style=\"color:red\">343K<\/span> |     343K |      |       |   . |    13.06 | Cpu (79)        |\n|    8 |         <span style=\"color:blue\">SORT JOIN<\/span>                  |                    |   28453 |   40 |       608 |     +1 |  343K |       4G |      |       | 1MB |    86.94 | Cpu (526)       |\n|    9 |          INDEX FAST FULL SCAN      | <span style=\"color:blue\">OBJ_CONT_INVDT#I#1<\/span> |   28453 |   30 |         1 |     +7 |     1 |    29971 |   55 |   4MB |   . |          |                 |\n=============================================================================================================================================================================<\/code><\/pre>\n<pre><code>   7 - filter(\"AX\".\"ATRX_SEQ_NR\"&lt;=\"CI\".\"TO_ATRX_SEQ_NR\")\n   8 - access(INTERNAL_FUNCTION(\"AX\".\"ATRX_SEQ_NR\")&gt;=INTERNAL_FUNCTION(\"CI\".\"FROM_ATRX_SEQ_NR\"))\n       filter(INTERNAL_FUNCTION(\"AX\".\"ATRX_SEQ_NR\")&gt;=INTERNAL_FUNCTION(\"CI\".\"FROM_ATRX_SEQ_NR\"))\n   9 - filter((\"CI\".\"FROM_ATRX_SEQ_NR\"&lt;=:B2 AND \"CI\".\"TO_ATRX_SEQ_NR\"&gt;=:B1))<\/code><\/pre>\n<p>Most of the time was spent on the <span style=\"color:blue\">SORT JOIN<\/span> operation.<\/p>\n<p>By comparing the number of rows retuned by the step 6 with the number of executions of the steps 7 and 8, it becomes obvious that the <span style=\"color:blue\">SORT JOIN<\/span> gets executed for every row returned by the step 6.<\/p>\n<p>In other words, <span style=\"color:blue\">SORT JOIN<\/span> on <span style=\"color:blue\">OBJ_CONT_INVDT<\/span> gets executed for rows from <span style=\"color:red\">ATRX<\/span>.<\/p>\n<p>This interpretation yield the following improvement ideas:<br \/>\n&#8211; reducing the number of query executions by selecting more than one <span style=\"color:red\">ATRX_SEQ_NR<\/span> (ROWNUM &lt;= n instead of ROWNUM &lt;= 1),<br \/>\n&#8211; reducing the number of <span style=\"color:blue\">SORT JOIN<\/span> operations by narrowing the filter defined by bind variables <span style=\"color:red\">:B2<\/span> and <span style=\"color:red\">:B1<\/span>,<br \/>\n&#8211; improving the efficiency of a single SORT JOIN operation by introducing a filter on <span style=\"color:blue\">OBJ_CONT_INVDT<\/span><\/p>\n<p>Last but not least, I built a model to reproduce the critical subset of the execution plan for further experimentation:<\/p>\n<pre><code>drop table t1 ;\ndrop table t2 ;\n\ncreate table t1 ( n1 number ) ;\ninsert into t1 select level from dual connect by level &lt;= 1000 ;\n\ncreate table t2 ( low_bound number, upper_bound number ) ;\ncreate index ix_t2 on t2 (upper_bound, low_bound) ;\ninsert into t2 select 400,500 from dual connect by level &lt;= 100 ;\n\ncommit ;\n\nexec dbms_stats.gather_table_stats(null,'T1') ;\nexec dbms_stats.gather_table_stats(null,'T2') ;\n\nselect \/*+ monitor *\/  n1 \n  from t1 \n  where not exists ( \n    select null \n      from t2 \n      where t1.n1 between t2.low_bound and t2.upper_bound  \n  ) ;\n  \nPlan hash value: 1610866028\n \n-----------------------------------------------------------------------------\n| Id  | Operation           | Name  | Rows  | Bytes | Cost (%CPU)| Time     |\n-----------------------------------------------------------------------------\n|   0 | SELECT STATEMENT    |       |   700 |  7000 |     5  (40)| 00:00:01 |\n|   1 |  MERGE JOIN ANTI    |       |   700 |  7000 |     5  (40)| 00:00:01 |\n|   2 |   SORT JOIN         |       |  1000 |  4000 |     3  (34)| 00:00:01 |\n|   3 |    TABLE ACCESS FULL| T1    |  1000 |  4000 |     2   (0)| 00:00:01 |\n|*  4 |   FILTER            |       |       |       |            |          |\n|*  5 |    SORT JOIN        |       |   100 |   600 |     2  (50)| 00:00:01 |\n|   6 |     INDEX FULL SCAN | IX_T2 |   100 |   600 |     1   (0)| 00:00:01 |\n-----------------------------------------------------------------------------\n \nPredicate Information (identified by operation id):\n---------------------------------------------------\n \n   4 - filter(\"T1\".\"N1\"&lt;=\"T2\".\"UPPER_BOUND\")\n   5 - access(INTERNAL_FUNCTION(\"T1\".\"N1\")&gt;=INTERNAL_FUNCTION(\"T2\".\"LOW_\n              BOUND\"))\n       filter(INTERNAL_FUNCTION(\"T1\".\"N1\")&gt;=INTERNAL_FUNCTION(\"T2\".\"LOW_\n              BOUND\"))<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Performance issue in the Avaloq backend\/frontend interface <a href=\"https:\/\/nenadnoveljic.com\/blog\/anti-join-with-range-predicate\/\" 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":[13,11,5,32],"tags":[],"class_list":["post-3812","post","type-post","status-publish","format-standard","hentry","category-avaloq","category-cost-based-optimizer","category-oracle","category-sort"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Anti Join with Range Predicate - All-round Database Topics<\/title>\n<meta name=\"description\" content=\"Performance issue in the Avaloq backend\/frontend interface\" \/>\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\/anti-join-with-range-predicate\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Anti Join with Range Predicate - All-round Database Topics\" \/>\n<meta property=\"og:description\" content=\"Performance issue in the Avaloq backend\/frontend interface\" \/>\n<meta property=\"og:url\" content=\"https:\/\/nenadnoveljic.com\/blog\/anti-join-with-range-predicate\/\" \/>\n<meta property=\"og:site_name\" content=\"All-round Database Topics\" \/>\n<meta property=\"article:published_time\" content=\"2021-06-29T16:47:42+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-06-29T16:49:09+00:00\" \/>\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=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/anti-join-with-range-predicate\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/anti-join-with-range-predicate\\\/\"},\"author\":{\"name\":\"Nenad Noveljic\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#\\\/schema\\\/person\\\/51458d9dd86dbbdd19f5add451d44efa\"},\"headline\":\"Anti Join with Range Predicate\",\"datePublished\":\"2021-06-29T16:47:42+00:00\",\"dateModified\":\"2021-06-29T16:49:09+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/anti-join-with-range-predicate\\\/\"},\"wordCount\":377,\"commentCount\":0,\"articleSection\":[\"Avaloq\",\"cost based optimizer\",\"Oracle\",\"sort\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/anti-join-with-range-predicate\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/anti-join-with-range-predicate\\\/\",\"url\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/anti-join-with-range-predicate\\\/\",\"name\":\"Anti Join with Range Predicate - All-round Database Topics\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#website\"},\"datePublished\":\"2021-06-29T16:47:42+00:00\",\"dateModified\":\"2021-06-29T16:49:09+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#\\\/schema\\\/person\\\/51458d9dd86dbbdd19f5add451d44efa\"},\"description\":\"Performance issue in the Avaloq backend\\\/frontend interface\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/anti-join-with-range-predicate\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/anti-join-with-range-predicate\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/anti-join-with-range-predicate\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Anti Join with Range Predicate\"}]},{\"@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":"Anti Join with Range Predicate - All-round Database Topics","description":"Performance issue in the Avaloq backend\/frontend interface","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\/anti-join-with-range-predicate\/","og_locale":"en_US","og_type":"article","og_title":"Anti Join with Range Predicate - All-round Database Topics","og_description":"Performance issue in the Avaloq backend\/frontend interface","og_url":"https:\/\/nenadnoveljic.com\/blog\/anti-join-with-range-predicate\/","og_site_name":"All-round Database Topics","article_published_time":"2021-06-29T16:47:42+00:00","article_modified_time":"2021-06-29T16:49:09+00:00","author":"Nenad Noveljic","twitter_card":"summary_large_image","twitter_creator":"@NenadNoveljic","twitter_misc":{"Written by":"Nenad Noveljic","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/nenadnoveljic.com\/blog\/anti-join-with-range-predicate\/#article","isPartOf":{"@id":"https:\/\/nenadnoveljic.com\/blog\/anti-join-with-range-predicate\/"},"author":{"name":"Nenad Noveljic","@id":"https:\/\/nenadnoveljic.com\/blog\/#\/schema\/person\/51458d9dd86dbbdd19f5add451d44efa"},"headline":"Anti Join with Range Predicate","datePublished":"2021-06-29T16:47:42+00:00","dateModified":"2021-06-29T16:49:09+00:00","mainEntityOfPage":{"@id":"https:\/\/nenadnoveljic.com\/blog\/anti-join-with-range-predicate\/"},"wordCount":377,"commentCount":0,"articleSection":["Avaloq","cost based optimizer","Oracle","sort"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/nenadnoveljic.com\/blog\/anti-join-with-range-predicate\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/nenadnoveljic.com\/blog\/anti-join-with-range-predicate\/","url":"https:\/\/nenadnoveljic.com\/blog\/anti-join-with-range-predicate\/","name":"Anti Join with Range Predicate - All-round Database Topics","isPartOf":{"@id":"https:\/\/nenadnoveljic.com\/blog\/#website"},"datePublished":"2021-06-29T16:47:42+00:00","dateModified":"2021-06-29T16:49:09+00:00","author":{"@id":"https:\/\/nenadnoveljic.com\/blog\/#\/schema\/person\/51458d9dd86dbbdd19f5add451d44efa"},"description":"Performance issue in the Avaloq backend\/frontend interface","breadcrumb":{"@id":"https:\/\/nenadnoveljic.com\/blog\/anti-join-with-range-predicate\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/nenadnoveljic.com\/blog\/anti-join-with-range-predicate\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/nenadnoveljic.com\/blog\/anti-join-with-range-predicate\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/nenadnoveljic.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Anti Join with Range Predicate"}]},{"@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\/3812","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=3812"}],"version-history":[{"count":1,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts\/3812\/revisions"}],"predecessor-version":[{"id":3829,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts\/3812\/revisions\/3829"}],"wp:attachment":[{"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/media?parent=3812"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/categories?post=3812"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/tags?post=3812"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}