{"id":4065,"date":"2013-02-07T11:43:27","date_gmt":"2013-02-07T19:43:27","guid":{"rendered":"http:\/\/3.209.169.194\/blogs\/paul\/?p=4065"},"modified":"2017-07-26T10:32:27","modified_gmt":"2017-07-26T17:32:27","slug":"tracking-page-splits-using-the-transaction-log","status":"publish","type":"post","link":"https:\/\/www.sqlskills.com\/blogs\/paul\/tracking-page-splits-using-the-transaction-log\/","title":{"rendered":"Tracking page splits using the transaction log"},"content":{"rendered":"<p style=\"text-align: justify;\">Whenever I&#8217;m teaching about index fragmentation I get asked how to track page splits proactively. This can be useful to discover fragmentation occurring in indexes you didn&#8217;t know had fragmentation problems, without running the <em>sys.dm_db_index_physical_stats<\/em>\u00a0DMV (see\u00a0<a href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-sys-dm_db_index_physical_stats\/\" target=\"_blank\" rel=\"noopener noreferrer\">here<\/a>\u00a0for how that works)\u00a0against all the indexes in your databases.\u00a0Today this came up multiple times, both in class and in email, so it&#8217;s time to bubble this blog post up to the top of the list.<\/p>\n<p style=\"text-align: justify;\">You might think this is easy, as there&#8217;s a page split counter in <em>sys.dm_db_index_operational_stats<\/em> and in the Access Methods perfmon object. However, neither of these distinguish between &#8216;good&#8217; splits and &#8216;nasty&#8217; splits, which are my terms :-). A &#8216;nasty&#8217; split is what we think of a just a page split &#8211; a data or index page having to split into two pages to make space for a record to be inserted or an existing record to expand. A &#8216;good&#8217; split is what the Storage Engine calls adding a page on the right-hand side of the index leaf level as part of inserting new records in an ascending key index (e.g. a clustered index with a bigint identity column as the cluster key).<\/p>\n<p style=\"text-align: justify;\">This is a really annoying as it makes both these methods of tracking page splits essentially useless.<\/p>\n<p style=\"text-align: justify;\">If you&#8217;re running SQL Server 2012 or later, the solution is to use Extended Events, based on the new <em>sqlserver.transaction_log<\/em> event. Jonathan wrote a great post <a href=\"https:\/\/www.sqlskills.com\/blogs\/jonathan\/tracking-problematic-pages-splits-in-sql-server-2012-extended-events-no-really-this-time\/\" target=\"_blank\" rel=\"noopener noreferrer\">here<\/a> that gives you the Extended Events sessions to use. Be careful of doing this on a product system though as there&#8217;s a lot of overhead from using that event.<\/p>\n<p style=\"text-align: justify;\">If you&#8217;re not running SQL Server 2012 or later, read on.<\/p>\n<p style=\"text-align: justify;\">Before the <em>sqlserver.transaction_log<\/em> event was added, there was (and still is) the <em>sqlserver.page_split<\/em> event but that does not distinguish between &#8216;good&#8217; splits and &#8216;nasty&#8217; splits either, so some post processing is involved (essentially reading the page referenced in the event to see if it really split or not).<\/p>\n<p>So what&#8217;s the answer?<\/p>\n<h2>Scanning the log for page splits<\/h2>\n<p style=\"text-align: justify;\">The easiest way to proactively see page splits occurring is to look in the transaction log. Whenever a page splits, an <em>LOP_DELETE_SPLIT<\/em> log record is generated so querying the transaction log can let you know what&#8217;s going on.<\/p>\n<p>Some simple code to do this is:<\/p>\n<pre class=\"brush: sql; title: ; toolbar: true; wrap-lines: true; notranslate\" title=\"\">\r\nSELECT\r\n    &#x5B;AllocUnitName] AS N'Index',\r\n    (CASE &#x5B;Context]\r\n        WHEN N'LCX_INDEX_LEAF' THEN N'Nonclustered'\r\n        WHEN N'LCX_CLUSTERED' THEN N'Clustered'\r\n        ELSE N'Non-Leaf'\r\n    END) AS &#x5B;SplitType],\r\n    COUNT (1) AS &#x5B;SplitCount]\r\nFROM\r\n    fn_dblog (NULL, NULL)\r\nWHERE\r\n    &#x5B;Operation] = N'LOP_DELETE_SPLIT'\r\nGROUP BY &#x5B;AllocUnitName], &#x5B;Context];\r\nGO\r\n<\/pre>\n<p>However, I don&#8217;t recommend doing this, for two reasons:<\/p>\n<ol>\n<li style=\"text-align: justify;\"><span style=\"line-height: 13px;\">Running\u00a0<em>fn_dblog<\/em>\u00a0will cause read I\/Os on the transaction log, which can cause performance issues, especially if you&#8217;re running the scanner regularly and it happens to coincide with a log backup, for instance.<\/span><\/li>\n<li style=\"text-align: justify;\">Log clearing is disabled while\u00a0<em>fn_dblog<\/em> is running, so on a system with a large amount of log to scan, this could interrupt the ability of the log to clear and cause log growth.<\/li>\n<\/ol>\n<p style=\"text-align: justify;\">If you&#8217;re running in the full or bulk-logged recovery model, I recommend scanning your log backups for page splits instead of your actual log. If you&#8217;re only running in the simple recovery model, and you *really* want to run the script regularly, you&#8217;re going to have to run the script just before each checkpoint operation clears the log. But still, be careful you don&#8217;t interrupt the log clearing process.<\/p>\n<h2>Scanning a log backup for page splits<\/h2>\n<p>There are two options for this, using the <em>fn_dump_dblog<\/em> function I blogged about <a href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/using-fn_dblog-fn_dump_dblog-and-restoring-with-stopbeforemark-to-an-lsn\/\" target=\"_blank\" rel=\"noopener noreferrer\">here<\/a>:<\/p>\n<ul>\n<li><span style=\"line-height: 13px;\">Scanning a log backup on a system other than the production system.<\/span><\/li>\n<li>Scanning a log backup on the production system.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">If \u00a0you choose to use a system other than the production system, then unless you have a restored copy of the database, you will not be able to get the index name, as <em>fn_dump_dblog<\/em> does not give you the name and you will not have the metadata to allow looking up the index name from the allocation unit ID in the log.<\/p>\n<p style=\"text-align: justify;\"><strong>Edit 8\/15\/13: Beware &#8211; we just found out from a customer system that uses this extensively that every time\u00a0<em>fn_dump_dblog<\/em>\u00a0is called, it creates a new hidden SQLOS scheduler and up to three threads, which will never go away and never be reused. Use with caution.<\/strong><\/p>\n<p style=\"text-align: justify;\"><strong>Edit 5\/15\/15: It\u2019s fixed in SQL Server 2012 SP2+ and SQL Server 2014. The fix won\u2019t be back-ported any earlier.<\/strong><\/p>\n<p style=\"text-align: justify;\">So I&#8217;ve created two scripts for you, for when the database is and isn&#8217;t available on the server where the backup is located. I&#8217;ll extend these in future posts.<\/p>\n<p>Have fun!<\/p>\n<p><strong>Scanning a log backup where the database is not available<\/strong><\/p>\n<pre class=\"brush: sql; title: ; toolbar: true; wrap-lines: true; notranslate\" title=\"\">\r\nSELECT\r\n    &#x5B;AllocUnitId],\r\n    (CASE &#x5B;Context]\r\n        WHEN N'LCX_INDEX_LEAF' THEN N'Nonclustered'\r\n        WHEN N'LCX_CLUSTERED' THEN N'Clustered'\r\n        ELSE N'Non-Leaf'\r\n    END) AS &#x5B;SplitType],\r\n    COUNT (1) AS &#x5B;SplitCount]\r\nFROM\r\n    fn_dump_dblog (NULL, NULL, N'DISK', 1, N'C:\\SQLskills\\SplitTest_log.bck',\r\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT)\r\nWHERE\r\n    &#x5B;Operation] = N'LOP_DELETE_SPLIT'\r\nGROUP BY &#x5B;AllocUnitId], &#x5B;Context];\r\nGO\r\n<\/pre>\n<p><strong>Scanning a log backup where the database is available<\/strong><\/p>\n<pre class=\"brush: sql; title: ; toolbar: true; wrap-lines: true; notranslate\" title=\"\">\r\nSELECT\r\n    CAST (&#x5B;s].&#x5B;name] AS VARCHAR) + '.' + CAST (&#x5B;o].&#x5B;name] AS VARCHAR) + '.' + CAST (&#x5B;i].&#x5B;name] AS VARCHAR) AS &#x5B;Index],\r\n    &#x5B;f].&#x5B;SplitType],\r\n    &#x5B;f].&#x5B;SplitCount]\r\nFROM\r\n    (SELECT\r\n        &#x5B;AllocUnitId],\r\n        (CASE &#x5B;Context]\r\n            WHEN N'LCX_INDEX_LEAF' THEN N'Nonclustered'\r\n            WHEN N'LCX_CLUSTERED' THEN N'Clustered'\r\n            ELSE N'Non-Leaf'\r\n        END) AS &#x5B;SplitType],\r\n        COUNT (1) AS &#x5B;SplitCount]\r\n    FROM\r\n        fn_dump_dblog (NULL, NULL, N'DISK', 1, N'C:\\SQLskills\\SplitTest_log.bck',\r\n            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,\r\n            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT)\r\n    WHERE\r\n        &#x5B;Operation] = N'LOP_DELETE_SPLIT'\r\n    GROUP BY &#x5B;AllocUnitId], &#x5B;Context]) f\r\nJOIN sys.system_internals_allocation_units &#x5B;a]\r\n    ON &#x5B;a].&#x5B;allocation_unit_id] = &#x5B;f].&#x5B;AllocUnitId]\r\nJOIN sys.partitions &#x5B;p]\r\n    ON &#x5B;p].&#x5B;partition_id] = &#x5B;a].&#x5B;container_id]\r\nJOIN sys.indexes &#x5B;i]\r\n    ON &#x5B;i].&#x5B;index_id] = &#x5B;p].&#x5B;index_id] AND &#x5B;i].&#x5B;object_id] = &#x5B;p].&#x5B;object_id]\r\nJOIN sys.objects &#x5B;o]\r\n    ON &#x5B;o].&#x5B;object_id] = &#x5B;p].&#x5B;object_id]\r\nJOIN sys.schemas &#x5B;s]\r\n    ON &#x5B;s].&#x5B;schema_id] = &#x5B;o].&#x5B;schema_id];\r\nGO\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Whenever I&#8217;m teaching about index fragmentation I get asked how to track page splits proactively. This can be useful to discover fragmentation occurring in indexes you didn&#8217;t know had fragmentation problems, without running the sys.dm_db_index_physical_stats\u00a0DMV (see\u00a0here\u00a0for how that works)\u00a0against all the indexes in your databases.\u00a0Today this came up multiple times, both in class and in [&hellip;]<\/p>\n","protected":false},"author":5,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[38,42,47,98,100],"tags":[],"class_list":["post-4065","post","type-post","status-publish","format-standard","hentry","category-example-scripts","category-fragmentation","category-indexes-from-every-angle","category-transaction-log","category-undocumented-commands"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Tracking page splits using the transaction log - Paul S. Randal<\/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\/paul\/tracking-page-splits-using-the-transaction-log\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Tracking page splits using the transaction log - Paul S. Randal\" \/>\n<meta property=\"og:description\" content=\"Whenever I&#8217;m teaching about index fragmentation I get asked how to track page splits proactively. This can be useful to discover fragmentation occurring in indexes you didn&#8217;t know had fragmentation problems, without running the sys.dm_db_index_physical_stats\u00a0DMV (see\u00a0here\u00a0for how that works)\u00a0against all the indexes in your databases.\u00a0Today this came up multiple times, both in class and in [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.sqlskills.com\/blogs\/paul\/tracking-page-splits-using-the-transaction-log\/\" \/>\n<meta property=\"og:site_name\" content=\"Paul S. Randal\" \/>\n<meta property=\"article:published_time\" content=\"2013-02-07T19:43:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2017-07-26T17:32:27+00:00\" \/>\n<meta name=\"author\" content=\"Paul Randal\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Paul Randal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/tracking-page-splits-using-the-transaction-log\/\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/tracking-page-splits-using-the-transaction-log\/\",\"name\":\"Tracking page splits using the transaction log - Paul S. Randal\",\"isPartOf\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#website\"},\"datePublished\":\"2013-02-07T19:43:27+00:00\",\"dateModified\":\"2017-07-26T17:32:27+00:00\",\"author\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/tracking-page-splits-using-the-transaction-log\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.sqlskills.com\/blogs\/paul\/tracking-page-splits-using-the-transaction-log\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/tracking-page-splits-using-the-transaction-log\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Tracking page splits using the transaction log\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#website\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/\",\"name\":\"Paul S. Randal\",\"description\":\"In Recovery...\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce\",\"name\":\"Paul Randal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g\",\"caption\":\"Paul Randal\"},\"sameAs\":[\"http:\/\/3.209.169.194\/blogs\/paul\"],\"url\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/author\/paul\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Tracking page splits using the transaction log - Paul S. Randal","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\/paul\/tracking-page-splits-using-the-transaction-log\/","og_locale":"en_US","og_type":"article","og_title":"Tracking page splits using the transaction log - Paul S. Randal","og_description":"Whenever I&#8217;m teaching about index fragmentation I get asked how to track page splits proactively. This can be useful to discover fragmentation occurring in indexes you didn&#8217;t know had fragmentation problems, without running the sys.dm_db_index_physical_stats\u00a0DMV (see\u00a0here\u00a0for how that works)\u00a0against all the indexes in your databases.\u00a0Today this came up multiple times, both in class and in [&hellip;]","og_url":"https:\/\/www.sqlskills.com\/blogs\/paul\/tracking-page-splits-using-the-transaction-log\/","og_site_name":"Paul S. Randal","article_published_time":"2013-02-07T19:43:27+00:00","article_modified_time":"2017-07-26T17:32:27+00:00","author":"Paul Randal","twitter_misc":{"Written by":"Paul Randal","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/tracking-page-splits-using-the-transaction-log\/","url":"https:\/\/www.sqlskills.com\/blogs\/paul\/tracking-page-splits-using-the-transaction-log\/","name":"Tracking page splits using the transaction log - Paul S. Randal","isPartOf":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#website"},"datePublished":"2013-02-07T19:43:27+00:00","dateModified":"2017-07-26T17:32:27+00:00","author":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce"},"breadcrumb":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/tracking-page-splits-using-the-transaction-log\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.sqlskills.com\/blogs\/paul\/tracking-page-splits-using-the-transaction-log\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/tracking-page-splits-using-the-transaction-log\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.sqlskills.com\/blogs\/paul\/"},{"@type":"ListItem","position":2,"name":"Tracking page splits using the transaction log"}]},{"@type":"WebSite","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#website","url":"https:\/\/www.sqlskills.com\/blogs\/paul\/","name":"Paul S. Randal","description":"In Recovery...","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.sqlskills.com\/blogs\/paul\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce","name":"Paul Randal","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g","caption":"Paul Randal"},"sameAs":["http:\/\/3.209.169.194\/blogs\/paul"],"url":"https:\/\/www.sqlskills.com\/blogs\/paul\/author\/paul\/"}]}},"_links":{"self":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/posts\/4065","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/comments?post=4065"}],"version-history":[{"count":0,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/posts\/4065\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/media?parent=4065"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/categories?post=4065"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/tags?post=4065"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}