{"id":2628,"date":"2019-07-07T17:36:21","date_gmt":"2019-07-07T17:36:21","guid":{"rendered":"https:\/\/nenadnoveljic.com\/blog\/?p=2628"},"modified":"2019-08-23T15:59:01","modified_gmt":"2019-08-23T15:59:01","slug":"extracting-query-block-optimizer-trace","status":"publish","type":"post","link":"https:\/\/nenadnoveljic.com\/blog\/extracting-query-block-optimizer-trace\/","title":{"rendered":"Extracting Query Block Information from Optimizer Trace"},"content":{"rendered":"<h1><a href=\"https:\/\/github.com\/nenadnoveljic\/blogs\/blob\/master\/extracting_query_block_optimizer_trace\/opt_qb.awk\">opt_qb.awk<\/a><\/h1>\n<p>The entries related to query blocks (QB) are normally scattered across the whole optimizer trace file. Therefore, it requires a lot of tedious searching, copying and pasting as well as scrolling back and forth just to get some basic information about a QB. This becomes even more awkward with large trace files containing hundreds of thousands of lines.<\/p>\n<p>For this reason, I wrote <a href=\"https:\/\/github.com\/nenadnoveljic\/blogs\/blob\/master\/extracting_query_block_optimizer_trace\/opt_qb.awk\">opt_qb.awk<\/a>, a gawk script that parses the optimizer trace and extracts the information about QBs, such as the best join order, cost, cardinality and applied query transformations (QT). It comes in handy, because it neatly displays all the QB related information on one place. Besides that, it prints the line numbers, so you can quickly position yourself within the trace file when looking for more detailed information.<\/p>\n<p>Among others, the script has proven invaluable for analyzing QTs and, for example, quickly getting a clue why a QT was (or wasn&#8217;t) performed.<\/p>\n<p>The usage is as follows:<\/p>\n<pre><code><a href=\"https:\/\/github.com\/nenadnoveljic\/blogs\/blob\/master\/extracting_query_block_optimizer_trace\/opt_qb.awk\">opt_qb.awk<\/a> [-v qb='qb_name'] optimizer_trace_file<\/code><\/pre>\n<p>Without the <i>qb<\/i> option, the script will display all of the QBs. For larger queries with multiple QBs, I usually focus on a single QB at a time.<\/p>\n<p>The single quotation marks are optional when the QB doesn&#8217;t contain any special characters.<\/p>\n<h1>Simple case<\/h1>\n<p>A very simple sample output looks as follows:<\/p>\n<pre><code><a href=\"https:\/\/github.com\/nenadnoveljic\/blogs\/blob\/master\/extracting_query_block_optimizer_trace\/opt_qb.awk\">opt_qb.awk<\/a> -v qb=QB_MAIN DB_ora_640_NOJPPD58.trc              \n---------------\n27 Registered qb: QB_MAIN 0x93fcb108 (HINT QB_MAIN)\n\n2830 Final cost for query block QB_MAIN (#1) - All Rows Plan:\n2831   Best join order: 1\n2832   Cost: 874.989877  Degree: 1  Card: 123159.000000  Bytes: 1354749.000000\n---------------<\/code><\/pre>\n<p>I disabled the join predicate pushdown transformation (JPPD) here, so the QB_MAIN was costed only once.<\/p>\n<h1>JPPD<\/h1>\n<p>In contrast, the QB_MAIN appears three times in the trace after enabling JPPD:<\/p>\n<pre><code><a href=\"https:\/\/github.com\/nenadnoveljic\/blogs\/blob\/master\/extracting_query_block_optimizer_trace\/opt_qb.awk\">opt_qb.awk<\/a> -v qb=QB_MAIN AVAR99_ora_640_JPPD58.trc\n---------------\n27 Registered qb: QB_MAIN 0xa2780858 (HINT QB_MAIN)\n3231 JPPD: Performing join predicate push-down <span style=\"color: brown;\">(final phase) from query block QB_MIDDLE (#3) to query block QB_INNER (#4)<\/span>\n3236 JPPD: Performing join predicate push-down (<span style=\"color: green;\">no transformation phase<\/span>) from query block <span style=\"color: blue;\">QB_MAIN (#1) to query block QB_MIDDLE (#3)<\/span>\n4412 Final cost for query block QB_MAIN (#1) - All Rows Plan:\n4413   Best join order: 1\n4414   <span style=\"color: green;\">Cost: 873.989676<\/span>  Degree: 1  Card: 123159.000000  Bytes: 1354749.000000\n---------------\n27 Registered qb: QB_MAIN 0xa2780858 (HINT QB_MAIN)\n4426 JPPD: Performing join predicate push-down <span style=\"color: brown;\">(final phase) from query block QB_MIDDLE (#3) to query block QB_INNER (#4)<\/span>\n4431 JPPD: Performing join predicate push-down (<span style=\"color: red;\">candidate phase<\/span>) <span style=\"color: blue;\">from query block QB_MAIN (#1) to query block QB_MIDDLE (#3)<\/span>\n5515 Final cost for query block QB_MAIN (#1) - All Rows Plan:\n5516   Best join order: 1\n5517   <span style=\"color: red;\">Cost: 1239149.505827<\/span>  Degree: 1  Card: 123159.000000  Bytes: 1231590.000000\n---------------\n27 Registered qb: QB_MAIN 0xa2780858 (HINT QB_MAIN)\n5539 <span style=\"color: brown;\">JPPD: Performing join predicate push-down (final phase) from query block QB_MIDDLE (#3) to query block QB_INNER (#4)<\/span>\n5547 JPPD: Performing join predicate push-down (<span style=\"color: green;\">no transformation phase<\/span>) <span style=\"color: blue;\">from query block QB_MAIN (#1) to query block QB_MIDDLE (#3)<\/span>\n6805 Final cost for query block QB_MAIN (#1) - All Rows Plan:\n6806   Best join order: 1\n6807   <span style=\"color: green;\">Cost: 873.989676<\/span>  Degree: 1  Card: 123159.000000  Bytes: 1354749.000000\n---------------<\/code><\/pre>\n<p>The information is presented in such a way, that we can immediately recognize that QB_MAIN contains two nested QBs, both of which can receive the pushed predicate. We can clearly see that two JPPDs were considered. One is <span style=\"color: blue;\">from QB_MAIN to QB_MIDDLE<\/span>. The other is <span style=\"color: brown;\">from QB_MIDDLE to QB_INNER<\/span>.<\/p>\n<p>By the way, notice how dispersed was the information for the first section:<br \/>\n&#8211; line 27: QB<br \/>\n&#8211; lines 3231-3236: JPPD<br \/>\n&#8211; lines 4412-4414: Summary<\/p>\n<p>And this was only a small trace file containing not more than 10000 lines.<\/p>\n<p>In the first section, the cost calculation was done without performing JPPD <span style=\"color: blue;\">from QB_MAIN to QB_MIDDLE<\/span> (&#8220;<span style=\"color: green;\">no transformation phase<\/span>&#8220;).<\/p>\n<p>The second section contains the result of the cost calculation with JPPD (&#8220;<span style=\"color: red;\">candidate phase<\/span>&#8220;).<\/p>\n<p>In the third section, the optimizer compares both scenarios and finally decides not to do JPPD, because of the lower cost.<\/p>\n<p>Before costing QB_MAIN, it was already decided that the other JPPD, that is <span style=\"color: brown;\">from QB_MIDDLE to QB_INNER<\/span>, will be performed (&#8220;<span style=\"color: brown;\">final phase<\/span>&#8220;), but the details of this JPPD costing are omitted because of invoking <a href=\"https:\/\/github.com\/nenadnoveljic\/blogs\/blob\/master\/extracting_query_block_optimizer_trace\/opt_qb.awk\">opt_qb.awk<\/a> with <i>-v qb=QB_MAIN<\/i>.<\/p>\n<h1>Transformed QBs<\/h1>\n<p>In the previous examples, the QB names were provided by a hint, for instance:<\/p>\n<pre><code>---------------\n44 Registered qb: <span style=\"color: orange;\">QB_INNER<\/span> 0x93fb9a78 (<span style=\"color: orange;\">HINT QB_INNER<\/span>)\n1963 Final cost for query block QB_INNER (#4) - All Rows Plan:\n1964   Best join order: 1\n1965   Cost: 6.002355  Degree: 1  Card: 10.000000  Bytes: 90.000000\n---------------<\/code><\/pre>\n<p>But a QB can be transformed and renamed, like in the example below:<\/p>\n<pre><code><a href=\"https:\/\/github.com\/nenadnoveljic\/blogs\/blob\/master\/extracting_query_block_optimizer_trace\/opt_qb.awk\">opt_qb.awk<\/a> DB_ora_640_JPPD58.trc\n...\n---------------\n2393 Registered qb: <span style=\"color: orange;\">SEL$7B95B515<\/span> 0x8c970b80 (<span style=\"color: orange;\">PUSHED PREDICATE QB_INNER; QB_MIDDLE; \"V_INNER\"@\"QB_MIDDLE\" 2<\/span>)\n5547 JPPD: Performing join predicate push-down (no transformation phase) from query block QB_MAIN (#1) to query block QB_MIDDLE (#3)\n5539 JPPD: Performing join predicate push-down (final phase) from query block QB_MIDDLE (#3) to query block QB_INNER (#4)\n6122 Final cost for query block SEL$7B95B515 (#4) - All Rows Plan:\n6123   Best join order: 1\n6124   Cost: 5.027187  Degree: 1  Card: 1.000000  Bytes: 9.000000\n---------------<\/code><\/pre>\n<p>This is the reason for displaying the QB origin &#8211; the information which might be hidden somewhere thousands of lines before the cost calculation.<\/p>\n<h1>Future plans<\/h1>\n<p>I wrote this script for my own use when analyzing optimizer issues. It has helped me to quickly understand some optimizer decisions and even discover new optimizer bugs.<\/p>\n<p>It&#8217;s still work in progress and I&#8217;ll keep enhancing it as I go.<\/p>\n<p>For the sake of convenience, I wrote it in gawk, which is installed on every Solaris and Linux server. I tested it, though, only on Solaris x64.<\/p>\n<p>If it grows more complex and hence more difficult to maintain, I&#8217;ll consider rewriting it in Python.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Programmatically extracting the query block information from the optimizer trace <a href=\"https:\/\/nenadnoveljic.com\/blog\/extracting-query-block-optimizer-trace\/\" 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":[11,28,5],"tags":[],"class_list":["post-2628","post","type-post","status-publish","format-standard","hentry","category-cost-based-optimizer","category-join-predicate-push-down-jppd","category-oracle"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Extracting Query Block Information from Optimizer Trace - All-round Database Topics<\/title>\n<meta name=\"description\" content=\"Programmatically extracting the query block information from the optimizer trace\" \/>\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\/extracting-query-block-optimizer-trace\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Extracting Query Block Information from Optimizer Trace - All-round Database Topics\" \/>\n<meta property=\"og:description\" content=\"Programmatically extracting the query block information from the optimizer trace\" \/>\n<meta property=\"og:url\" content=\"https:\/\/nenadnoveljic.com\/blog\/extracting-query-block-optimizer-trace\/\" \/>\n<meta property=\"og:site_name\" content=\"All-round Database Topics\" \/>\n<meta property=\"article:published_time\" content=\"2019-07-07T17:36:21+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-08-23T15:59:01+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=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/extracting-query-block-optimizer-trace\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/extracting-query-block-optimizer-trace\\\/\"},\"author\":{\"name\":\"Nenad Noveljic\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#\\\/schema\\\/person\\\/51458d9dd86dbbdd19f5add451d44efa\"},\"headline\":\"Extracting Query Block Information from Optimizer Trace\",\"datePublished\":\"2019-07-07T17:36:21+00:00\",\"dateModified\":\"2019-08-23T15:59:01+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/extracting-query-block-optimizer-trace\\\/\"},\"wordCount\":592,\"commentCount\":0,\"articleSection\":[\"cost based optimizer\",\"join predicate push-down (JPPD)\",\"Oracle\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/extracting-query-block-optimizer-trace\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/extracting-query-block-optimizer-trace\\\/\",\"url\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/extracting-query-block-optimizer-trace\\\/\",\"name\":\"Extracting Query Block Information from Optimizer Trace - All-round Database Topics\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#website\"},\"datePublished\":\"2019-07-07T17:36:21+00:00\",\"dateModified\":\"2019-08-23T15:59:01+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#\\\/schema\\\/person\\\/51458d9dd86dbbdd19f5add451d44efa\"},\"description\":\"Programmatically extracting the query block information from the optimizer trace\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/extracting-query-block-optimizer-trace\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/extracting-query-block-optimizer-trace\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/extracting-query-block-optimizer-trace\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Extracting Query Block Information from Optimizer Trace\"}]},{\"@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":"Extracting Query Block Information from Optimizer Trace - All-round Database Topics","description":"Programmatically extracting the query block information from the optimizer trace","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\/extracting-query-block-optimizer-trace\/","og_locale":"en_US","og_type":"article","og_title":"Extracting Query Block Information from Optimizer Trace - All-round Database Topics","og_description":"Programmatically extracting the query block information from the optimizer trace","og_url":"https:\/\/nenadnoveljic.com\/blog\/extracting-query-block-optimizer-trace\/","og_site_name":"All-round Database Topics","article_published_time":"2019-07-07T17:36:21+00:00","article_modified_time":"2019-08-23T15:59:01+00:00","author":"Nenad Noveljic","twitter_card":"summary_large_image","twitter_creator":"@NenadNoveljic","twitter_misc":{"Written by":"Nenad Noveljic","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/nenadnoveljic.com\/blog\/extracting-query-block-optimizer-trace\/#article","isPartOf":{"@id":"https:\/\/nenadnoveljic.com\/blog\/extracting-query-block-optimizer-trace\/"},"author":{"name":"Nenad Noveljic","@id":"https:\/\/nenadnoveljic.com\/blog\/#\/schema\/person\/51458d9dd86dbbdd19f5add451d44efa"},"headline":"Extracting Query Block Information from Optimizer Trace","datePublished":"2019-07-07T17:36:21+00:00","dateModified":"2019-08-23T15:59:01+00:00","mainEntityOfPage":{"@id":"https:\/\/nenadnoveljic.com\/blog\/extracting-query-block-optimizer-trace\/"},"wordCount":592,"commentCount":0,"articleSection":["cost based optimizer","join predicate push-down (JPPD)","Oracle"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/nenadnoveljic.com\/blog\/extracting-query-block-optimizer-trace\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/nenadnoveljic.com\/blog\/extracting-query-block-optimizer-trace\/","url":"https:\/\/nenadnoveljic.com\/blog\/extracting-query-block-optimizer-trace\/","name":"Extracting Query Block Information from Optimizer Trace - All-round Database Topics","isPartOf":{"@id":"https:\/\/nenadnoveljic.com\/blog\/#website"},"datePublished":"2019-07-07T17:36:21+00:00","dateModified":"2019-08-23T15:59:01+00:00","author":{"@id":"https:\/\/nenadnoveljic.com\/blog\/#\/schema\/person\/51458d9dd86dbbdd19f5add451d44efa"},"description":"Programmatically extracting the query block information from the optimizer trace","breadcrumb":{"@id":"https:\/\/nenadnoveljic.com\/blog\/extracting-query-block-optimizer-trace\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/nenadnoveljic.com\/blog\/extracting-query-block-optimizer-trace\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/nenadnoveljic.com\/blog\/extracting-query-block-optimizer-trace\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/nenadnoveljic.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Extracting Query Block Information from Optimizer Trace"}]},{"@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\/2628","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=2628"}],"version-history":[{"count":1,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts\/2628\/revisions"}],"predecessor-version":[{"id":2883,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts\/2628\/revisions\/2883"}],"wp:attachment":[{"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/media?parent=2628"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/categories?post=2628"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/tags?post=2628"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}