{"id":89504,"date":"2021-01-11T17:32:54","date_gmt":"2021-01-11T17:32:54","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=89504"},"modified":"2021-07-14T13:06:50","modified_gmt":"2021-07-14T13:06:50","slug":"oracle-archived-redo-size-research","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/oracle-databases\/oracle-archived-redo-size-research\/","title":{"rendered":"Oracle archived redo size \u2013 the research"},"content":{"rendered":"<p>In an <a href=\"https:\/\/www.red-gate.com\/simple-talk\/sql\/oracle\/are-your-oracle-archived-log-files-much-too-small\/\">earlier article<\/a>, I explained why you might see log file switches taking place much more frequently than expected, with the <strong><em>archived<\/em><\/strong> redo files being much smaller than the <strong><em>online<\/em><\/strong> redo log files.<\/p>\n<p>When I do presentations about the odd effects that can appear in a fairly ordinary Oracle system, I\u2019m often asked what I did to work out what was happening under the covers. In this article, I will describe a few of the steps I took to investigate this aspect of the logging and archiving mechanism. It\u2019s not rocket science, and most of the time, all I ever do is use methods that have been available for decades.<\/p>\n<h2>cpu_count<\/h2>\n<p>I started with a review of some default parameter settings and the resulting allocation of public and private redo strands. Somewhere along the line, I pointed out that with <em>\u201cmy cpu_count of 48\u201d<\/em> I got 3 public redo strands.<\/p>\n<p>I don\u2019t actually have a laptop with 48 CPUs \u2013 I have a laptop with a single core and 4 CPUs that can do double-threading to look like 8 CPUs, and I was running 19c in a virtual machine configured with 4 CPUs. I set the <code>cpu_count<\/code> parameter to 48 and restarted the instance \u2013 which still told me I had only 4 CPUs until I also set the parameter <code>_disable_cpu_check<\/code> to <em>true<\/em>. Now, after startup, I see the following:<\/p>\n<pre class=\"lang:tsql decode:true \">SQL&gt; show parameter cpu<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-89523\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/cpucount.jpg\" alt=\"CPU count results\" width=\"937\" height=\"163\" \/><\/p>\n<p>Given that I was going to mess with parameters a lot, I switched from a binary <em>spfile<\/em> to a pure text <em>pfile<\/em>, (<code>create pfile from spfile<\/code> command) and ended up issuing the following pair of commands fairly frequently:<\/p>\n<p>shutdown transactional<\/p>\n<pre class=\"lang:tsql decode:true \">startup pfile=\u2019.\/initor19.ora\u2019<\/pre>\n<p>That should tell you how I decided that <strong><em>processes <\/em><\/strong>defaults to 80 * <strong><em>cpu_count<\/em><\/strong> + 40 and found that the manual was slightly wrong in its statement about the default value of <strong><em>sessions<\/em><\/strong> (actually 1.5 * <strong><em>processes<\/em><\/strong> + 24) but correct in its statement about <strong><em>transactions<\/em><\/strong> (1.1 * <strong><em>sessions<\/em><\/strong>). I kept restarting the instance after changing the <strong><em>cpu_count<\/em><\/strong> in my <em>pfile<\/em> to see how the other parameters changed.<\/p>\n<h2>Redo Strands and In-Memory Undo (IMU)<\/h2>\n<p>In the previous article, I mentioned the existence of <code>x$<\/code> structures but used <code>v$latch_children<\/code> to find out more about in-memory undo and redo strands. If you want access to the memory for redo strands and in-memory undo, you can query <code>x$kcrfstrand<\/code> (redo strands) and <code>x$ktifp<\/code> (in-memory undo) while connected as <strong><em>sys<\/em><\/strong>. First, the redo strands:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">select\r\n        ptr_kcrf_pvt_strand,\r\n        first_buf_kcrfa,\r\n        last_buf_kcrfa,\r\n        total_bufs_kcrfa,\r\n        strand_size_kcrfa,\r\n        indx\r\nfrom\r\n        x$kcrfstrand\r\n\/<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"970\" height=\"265\" class=\"wp-image-89505\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/word-image-48.png\" \/><\/p>\n<p>This output shows 3 (= 48\/16) public redo strands using 7,856,128 bytes of memory each, and 7 private strands using 132,096 bytes of memory each. The latter was surprising since the number of <strong><em>redo allocation latches<\/em><\/strong> told me I should have 644 private strands. Possibly there\u2019s some memory effect that stopped this from happening, or it\u2019s an initial allocation that grows dynamically on demand. Still, I\u2019ve actually been able to disable private redo strands completely by setting an \u201cunlucky\u201d size for the <code>log_buffer<\/code> parameter which left me with no private strands on startup and resulted in the system activity statistics incrementing the <em>\u201cIMU pool not allocated\u201d<\/em> and <em>\u201cIMU- failed to get a private strand\u201d<\/em> statistics on every transaction.<\/p>\n<p>Now the in-memory undo:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">select\r\n        ktifpno,\r\n        ktifpxcb                                tx_addr,\r\n        ktifpupb                                undo_start,\r\n        ktifpupc                                undo_cur,\r\n        to_number(ktifpupc,'XXXXXXXXXXXXXXXX') -\r\n                to_number(ktifpupb,'XXXXXXXXXXXXXXXX')  undo_usage,\r\n        ktifprpb                                redo_start,\r\n        ktifprpc                                redo_cur,\r\n        to_number(ktifprpc,'XXXXXXXXXXXXXXXX') -\r\n                to_number(ktifprpb,'XXXXXXXXXXXXXXXX')  redo_usage,\r\n        ktifptxflg\r\nfrom\r\n        x$ktifp\r\n\/<\/pre>\n<p>I\u2019ve selected all the rows from this structure (but deleted most of them) to show that Oracle had allocated all 644 even though it had only allocated a few of the private redo strands. If I wanted to query this structure for troubleshooting purposes, I\u2019d probably add the predicate: <code>where tx_addr != hextoraw('00')<\/code> to limit the output to just the strands currently in use.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"152\" class=\"wp-image-89506\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/word-image-49.png\" \/><\/p>\n<h2>The log buffer and the log file<\/h2>\n<p>The next step was checking the connection between the log buffer \/ public strands and the log file. I had set the <code>log_buffer<\/code> parameter to 60MB with 3 public strands and a log file of 65MB and then made a single process do a lot of work. After seeing the effect on the size of the archived redo log file, I made the initial hypothesis that the three strands had been mapped to 3 areas in the log file. What could I do to confirm this hypothesis?<\/p>\n<p>When I had my 3 strands of 20MB, the first 3 rows of <code>x$kcrfstrand<\/code> looked like this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1021\" height=\"115\" class=\"wp-image-89507\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/word-image-50.png\" \/><\/p>\n<p>Notice the addresses given in the <code>first_buf_kcrfa<\/code> and the gaps between them:<\/p>\n<ul>\n<li>0x00000002DE800000 &#8211; 0x00000002DD400000 = 0x1400000 = 20971520 (dec) = 20MB<\/li>\n<li>0x00000002DD400000 &#8211; 0x00000002DC000000 = 0x1400000 = 20971520 (dec) = 20MB<\/li>\n<\/ul>\n<p>You might assume that the three addresses are the starting addresses of the three memory areas of 20MB each. Take a look at the actual memory content by logging in as a privileged user and executing:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"460\" height=\"95\" class=\"wp-image-89508\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/word-image-51.png\" \/><\/p>\n<p>The <code>oradebug peek<\/code> commands will dump 4,096 (= 8 * 512) bytes starting at the memory location given (note the 0x prefix) to the session trace file and will also echo the first few of those bytes on screen. Here are the first 20 bytes that appeared on screen for the three calls:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"814\" height=\"75\" class=\"wp-image-89509\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/word-image-52.png\" \/><\/p>\n<p>A couple of numbers stand out here \u2013 the leading 00002201 (but I don\u2019t know what that means) and the 0000025E that repeats down the list, which was the sequence number (<code>v$log.sequence#<\/code>) of the current online redo log file.<\/p>\n<p>Using the UNIX <code>grep<\/code> command to find more occurrences of 00000253 in the trace files here are a few lines the first peek command:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"778\" height=\"99\" class=\"wp-image-89510\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/word-image-53.png\" \/><\/p>\n<p>from the second peek:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"733\" height=\"92\" class=\"wp-image-89511\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/word-image-54.png\" \/><\/p>\n<p>and the third peek:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"760\" height=\"96\" class=\"wp-image-89512\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/word-image-55.png\" \/><\/p>\n<p>The left-hand column is the memory address; the next 4 columns hold the 16 bytes starting at that memory address. As you can see, the lines that <code>grep<\/code> has selected show memory addresses that are separated by 512 (hex 0x200) bytes and the second column is incrementing by one every time. The seco<\/p>\n<p>nd column is the block number within the redo log file where each block of 512 bytes will be written.<\/p>\n<p>There\u2019s an important detail here. The <strong><em>block within file<\/em><\/strong> numbers aren\u2019t consistent with blocks that are 20MB apart from each other (the gaps are approximately 0x2000 blocks, i.e. roughly 4MB). This shows that even though Oracle may have allocated three areas of 20MB in the log file, it hasn\u2019t mapped each 20MB of file to a corresponding contiguous 20MB of memory; the mechanisms for using the memory must be a little more sophisticated than that.<\/p>\n<p>To get a finer grained view of the activity, I changed the test to execute a larger number of smaller transactions and then started stepping through a redo strand 512 bytes (one block) at a time dumping 16 bytes at each step. I used a little PL\/SQL to write a script to do this:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">declare\r\n        n1 number := to_number('&amp;m_head','XXXXXXXXXXXXXXXX');\r\nbegin\r\n        for i in 0 .. 127 loop\r\n                dbms_output.put_line(\r\n\t\t\t\t'oradebug peek 0x' ||   \r\n\t\t\t\tto_char(n1 + 512 * i , 'FMXXXXXXXXXXXXXXXX') || \r\n\t\t\t\t' 16'\r\n\t\t\t);\r\n        end loop;\r\nend;\r\n\/ <\/pre>\n<p>This script produced a list of <code>oradebug peek {address} 16<\/code> commands that I spooled to a file then executed from SQL*Plus. You\u2019ll see that I\u2019ve got a substitution variable <code>&amp;m_head<\/code> that I used to supply the starting address of a redo strand. Here are the results from the start of the first of the three redo strands in the latest test &#8211; the 0X2AD in the penultimate column tells you that I\u2019ve switched log files several times since my previous experiments.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"671\" height=\"289\" class=\"wp-image-89513\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/word-image-56.png\" \/><\/p>\n<p>You\u2019ll notice that this redo strand starts with blocks 0x2 to 0x15 of the redo file then jumps to block 0x19 and gets as far as block 0x1F before leaving another gap and jumping to block 0x30.<\/p>\n<p>When executing the list of peeks into the second redo strand, you can discover the \u201cmissing\u201d blocks:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"662\" height=\"127\" class=\"wp-image-89514\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/word-image-57.png\" \/><\/p>\n<p>The result tells us that there\u2019s something very dynamic about how Oracle handles the mapping between the redo log file and the in-memory public redo strands. Even though Oracle seems to use the size of the public redo strands as a sort of \u201crationing\u201d mechanism, it\u2019s not hard mapping from memory to file. This is good since the log writer would otherwise be making huge jumps around the redo log file to write it every time a session issued a commit. The appearance of large gaps in the lists of block numbers in the previous test must have been something to do with the sizes and numbers of concurrent transactions.<\/p>\n<h2>Next Steps<\/h2>\n<p>At this point, it\u2019s important to pause for a moment to consider what\u2019s been learned.\u00a0The experiment established (with a reasonable degree of confidence) that\u00a0the number of CPUs and the value of the\u00a0<b><i>log_buffer<\/i><\/b>\u00a0parameter have a critical impact on the size and number of the public redo threads and the potential \u201cwastage\u201d of space in the redo log files. You have determined that the <em>actual<\/em> wastage is then affected by the degree of concurrency of the work going on, and have noted that the pattern of the work (small or large transactions) may make some difference to the way writes to the redo log files are scattered.<\/p>\n<p>The question at this point is \u2013 <em>\u201cwhat do we <\/em><strong><em>need<\/em><\/strong><em> to do next?\u201d<\/em> The answer, I think, is <em>\u201cNothing\u201d<\/em>.<\/p>\n<p>So far, what\u2019s been learned provides an argument for picking a suitable size for the redo log files. Any further investigations are probably <strong><em>not<\/em><\/strong> going to tell anything useful. This is an excellent moment to stop digging unless you\u2019re seeing some further problem that hasn\u2019t yet been addressed.<\/p>\n<p>On the other hand, there may be some interesting little details waiting to be discovered, and maybe there\u2019s something that might turn out to be useful in a couple of years\u2019 time. Here are a few more thoughts and observations and a few pointers on how to get started \u2013 for entertainment value only \u2013 that you might think about investigating.<\/p>\n<h2>Open Questions<\/h2>\n<p>Is the (hypothesized) block number seen in the in-memory redo thread really used to identify the location where that bit of the thread will be written, or is it just a hang-over from a time when the redo writing mechanism was much simpler?<\/p>\n<p>When Oracle writes to the redo log file, does it write sequentially or will it have to jump around the log file? (Is this question answered by the previous one?)<\/p>\n<p>When recovery is taking place, will Oracle read the log file sequentially or will it have to jump around the log file to read redo records in the correct SCN order? (Is this also addressed by the first question?)<\/p>\n<p>Will a single transaction be associated with a single public redo thread until it commits? (If so, how would this affect scalability in the face of a lot of highly concurrent activity?)<\/p>\n<p>One strategy to start finding answers to these questions is simply to dump an archived log file and start comparing the \u201clogical\u201d dump with a raw physical dump.<\/p>\n<p>If you are interested in extending your understanding of the <strong>activity<\/strong> as Oracle handles redo, there\u2019s some interesting material in Oracle Core (ISBN 978-1-4302-3955-0). However, for a very detailed examination of the concurrency issues and all the latching that goes on as Oracle moves data between sessions, private redo strands, public redo strands and the log files, Frits Hoogland has spent a lot of time in recent years investigating and writing up the details on his blog. A good starting point would be: <a href=\"https:\/\/fritshoogland.wordpress.com\/2018\/01\/29\/a-look-into-oracle-redo-part-1-redo-allocation-latches\/\">https:\/\/fritshoogland.wordpress.com\/2018\/01\/29\/a-look-into-oracle-redo-part-1-redo-allocation-latches\/<\/a><\/p>\n<h2>Looking at log files<\/h2>\n<p>After generating a little over 70 MB of redo by starting three concurrent processes in a loop doing many multi-row updates with commits so that Oracle filled and archived the current log file, I dumped the entire archived log file using the basic command:<\/p>\n<p>alter system dump logfile {archived_log_filename};<\/p>\n<p>Be careful when doing this, the archived log file was just under 65MB, but the trace file was just over 374MB. If you want to see what\u2019s happening with a single transaction, you could limit the log file dump to a single transaction. Modify the update code to report transaction IDs (from <strong><em>v$tranaction.xidusn<\/em><\/strong>, <strong><em>xidslot<\/em><\/strong> and <strong><em>xidsqn<\/em><\/strong>) just before each commit and use one of the transaction triplets in the following command:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk \">alter system dump logfile {archived_log_filename}\r\nxid {xidusn} {xidslot} {xidsqn};<\/pre>\n<p>One thing to pick out from the trace file would be an ordered list of <em>\u201cRedo Records\u201d<\/em>. Here\u2019s how to find their headers with a simple <code>grep<\/code> command \u2013 or an <code>egrep<\/code> command if you want the <em>\u201cChange Vectors\u201d<\/em> at the same time:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">grep -n \"^REDO RECORD\" {tracefile_name}\r\negrep -n -e \"^REDO RECORD\" -e \"^CHANGE\" {tracefile_name}<\/pre>\n<p>Here are the first few lines of output from my trace file (by this time I was on log file sequence 768 \/ 0x300)<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"961\" height=\"76\" class=\"wp-image-89515\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/word-image-58.png\" \/><\/p>\n<p>The thing to pick out is the three-part <strong><em>RBA<\/em><\/strong> (redo byte address) which consists of <code>{sequence#.block#.byte#}<\/code> which tells you exactly where in the file the redo record starts. An interesting bit appeared further down my file:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"968\" height=\"148\" class=\"wp-image-89516\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/word-image-59.png\" \/><\/p>\n<p>Take a look at the block numbers: to display these redo records in order (i.e. in SCN order) Oracle is jumping around three different areas of the archived redo log file. It\u2019s important to spot backwards jumps, of course; if all you see are forward jumps, then that may simply be a timing\/delay effect.<\/p>\n<p>This result <strong><em>suggests<\/em><\/strong> two things: first, recovery does not read a log file sequentially to apply redo at the roll-forward stage; if your system uses multiple redo threads, recovery may be doing far more random I\/Os than you had expected. Secondly, when Oracle writes to the redo log file the log writer (or each log writer slave) must be doing something far more complicated than it did in older versions \u2013 a writer may be turning a single contiguous piece of log buffer into a number of separate writes corresponding to the different areas of the log file, and that may have to be done with each public strand in turn for a fairly large number of commits.<\/p>\n<p>Of course, it\u2019s just possible (though it seems very unlikely) that with multiple private strands the RBA is no longer an indicator of the truth, maybe RBA 0x000300.0000200d.0014 no longer means the redo record at byte 0x14 of block 0x200d; but you can check that very easily with an O\/S block dump. Block 0x200D (8205) will start after 8204 * 512 bytes so a suitable <strong><em>od<\/em><\/strong> (octal dump) command would be:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">od -j4200960 -N512 -Ad -x {archived_log_filename}<\/pre>\n<p>This skips 4,200,960 bytes, prints 512 bytes, gives the address in decimal, and the values in hexadecimal, with the following results for the first 48 bytes of the block:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"511\" height=\"59\" class=\"wp-image-89517\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/word-image-60.png\" \/><\/p>\n<p>You\u2019ll spot the 2201, 200d, 300 in the first line here that identify the block and conform to the three (8 byte) values stored at the start of each block in a public strand \u2013 so the RBA does mean what it says \u2013 and if you look at the whole redo record, you could start matching the contents of the O\/S dump with the log file dump:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"955\" height=\"82\" class=\"wp-image-89518\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/01\/word-image-61.png\" \/><\/p>\n<p>As a starting point, the first obvious match is the <em>LEN: 0x0780<\/em> with the <em>0780<\/em> that appears at the 20<sup>th<\/sup> byte, another easy match is the <em>SCN 0x00000b860fc4d7d7 \/ 0b86 d7d7 0fc4<\/em> and <em>SUBSCN 13 \/ 000d<\/em><\/p>\n<p>It looks as if any data in the public strands is copied directly to the log files, and the block address shown in each 512 byte block of memory really is the file block number that the data will be written to. Still, it may take a few more experiments to make us confident that that really is the case.<\/p>\n<h2>Conclusion<\/h2>\n<p>This article has been an exercise in demonstrating a few tools to poke around inside Oracle to get a broad idea of how some parts of the code are probably working. There hasn\u2019t been much arcane knowledge needed; every tool or mechanism I\u2019ve mentioned has been written about many times in the last 30 years.<\/p>\n<p>In summary, the article:<\/p>\n<ul>\n<li>Tweaked a couple of parameters (one of them a hidden parameter)<\/li>\n<li>Took advantage of starting Oracle with a <strong><em>pfile<\/em><\/strong> instead of an <strong><em>spfile<\/em><\/strong><\/li>\n<li>Queried <strong><em>v$latch_children<\/em><\/strong><\/li>\n<li>Mentioned <strong><em>v$log.sequence#<\/em><\/strong><\/li>\n<li>Queried <strong><em>x$kcrfstrand<\/em><\/strong> and <strong><em>x$ktifp<\/em><\/strong> \u2013 the closest you got to rocket science<\/li>\n<li>Used the <strong><em>oradebug peek<\/em><\/strong> command<\/li>\n<li>Used a couple of <strong><em>grep<\/em><\/strong> and <strong><em>egrep<\/em><\/strong> commands<\/li>\n<li>Looked for patterns in lists of numbers and made a couple of guesses<\/li>\n<\/ul>\n<p>Then, considering options for further digging, we:<\/p>\n<ul>\n<li>Used a couple of <strong><em>\u201cdump logfile\u201d<\/em><\/strong> options of the <strong><em>alter system<\/em><\/strong> command<\/li>\n<li>Used the <strong><em>od<\/em><\/strong> command to view the raw contents of a file<\/li>\n<\/ul>\n<p>What this proved (with some degree of confidence) is why the effective size of the online redo logs (as seen in the archived redo logs) isn\u2019t always the same as the actual size, and how the log writer process and any \u201crecover\/replay\u201d mechanism may have to do more work than it used to in earlier versions of Oracle to deal with the multiple public redo strands.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Oracle archived redo size may be smaller than that of online redo log files. In this article, Jonathan Lewis takes a deeper look.&hellip;<\/p>\n","protected":false},"author":101205,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[53,143533],"tags":[4459],"coauthors":[39048],"class_list":["post-89504","post","type-post","status-publish","format-standard","hentry","category-featured","category-oracle-databases","tag-oracle"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/89504","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/101205"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=89504"}],"version-history":[{"count":7,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/89504\/revisions"}],"predecessor-version":[{"id":89520,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/89504\/revisions\/89520"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=89504"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=89504"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=89504"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=89504"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}