{"id":1422,"date":"2018-07-25T12:21:00","date_gmt":"2018-07-25T12:21:00","guid":{"rendered":"https:\/\/www.tiagoneves.net\/blog\/?p=1422"},"modified":"2018-07-26T12:49:33","modified_gmt":"2018-07-26T12:49:33","slug":"replique-os-backups-de-sua-vm-sql-server-do-azure-para-amazon","status":"publish","type":"post","link":"https:\/\/www.tiagoneves.net\/blog\/replique-os-backups-de-sua-vm-sql-server-do-azure-para-amazon\/","title":{"rendered":"Replique os backups de sua VM SQL Server do Azure para Amazon"},"content":{"rendered":"<p>Ol\u00e1 pessoal, tudo certo?<\/p>\n<p>No post de hoje vou compartilhar com voc\u00eas um caso que atendi em um de nossos clientes.<\/p>\n<p>O nosso cliente tem uma VM com o SQL Server no<strong> Azure<\/strong> e gostaria de ter um site de <strong>DR (disaster recovery)<\/strong> na<strong> Amazon<\/strong>. At\u00e9 ai tudo bem, voc\u00ea poderia falar &#8220;Tiago isso \u00e9 f\u00e1cil, o SQL Server te d\u00e1 tantas possibilidades&#8221; ou at\u00e9 mesmo &#8220;Poxa ele pode usar a replica\u00e7\u00e3o no pr\u00f3prio Azure&#8221;. Concordo com tudo isso, mas cliente \u00e9 cliente e a solicita\u00e7\u00e3o era &#8220;Quero uma c\u00f3pia do meu SQL Server na Amazon&#8221;. Ent\u00e3o a replica\u00e7\u00e3o no pr\u00f3prio Azure est\u00e1 descartada.<\/p>\n<p>Pensei em utilizar o <strong>AlwaysOn AG<\/strong>, por\u00e9m, a licen\u00e7a que ele utiliza \u00e9 a edi\u00e7\u00e3o Web que n\u00e3o tem suporte. Ent\u00e3o AG descartado.<\/p>\n<p>Passamos para pr\u00f3xima possibilidade que \u00e9 configurar uma <strong>Replica\u00e7\u00e3o<\/strong>. S\u00f3 que o custo (esfor\u00e7o) para configurar seria grande, mas seria uma alternativa v\u00e1lida tamb\u00e9m.<\/p>\n<p>Pr\u00f3ximo cen\u00e1rio seria configurar um <strong>Database Mirror<\/strong>, por\u00e9m como os servidores est\u00e3o em clouds diferentes que n\u00e3o est\u00e3o integradas, ter\u00edamos que configurar o mirror utilizando certificado, mesmo assim n\u00e3o seria poss\u00edvel seguir com esse cen\u00e1rio, pois a edi\u00e7\u00e3o Web libera voc\u00ea para configurar o servidor apenas como testemunha (<strong>witness<\/strong>).<\/p>\n<p>Ent\u00e3o chegamos no cen\u00e1rio que melhor atendeu a situa\u00e7\u00e3o que \u00e9 configurar um <strong>Log Shipping<\/strong>. Contudo, ter\u00edamos um esfor\u00e7o grande pelo mesmo motivo do mirror&#8230; &#8220;clouds diferentes n\u00e3o integradas&#8230;&#8221;, mas a\u00ed que entra uma solu\u00e7\u00e3o de contorno que \u00e9 criar um <strong>Log Shipping manual<\/strong>, que nada mais \u00e9 que pegar os backups de um servidor e restaurar no outro.<\/p>\n<p><span style=\"color: #808080;\"><strong>Mas Tiago como que voc\u00ea copia os backups de um servidor para o outro? Utilizou alguma ferramenta? FTP?<\/strong><\/span><\/p>\n<p><strong><span style=\"color: #ff0000;\">Resposta: N\u00e3o.<\/span><\/strong><\/p>\n<p>Poder\u00edamos utilizar ferramentas para copiar os backups ou transferir via FTP, s\u00f3 que o nosso servi\u00e7o foi facilitado pelo cliente j\u00e1 que ele utiliza o servi\u00e7o de backup direto em um Blob Storage, se voc\u00ea quiser conhecer esse servi\u00e7o veja o post (<a href=\"https:\/\/www.tiagoneves.net\/blog\/fazendo-um-backup-database-no-azure\/\" target=\"_blank\" rel=\"noopener\">Fazendo um backup database On-Premises no Azure<\/a>). Portanto, no servidor da Amazon eu precisaria apenas fazer o restore sem precisa de copiar os arquivos.<\/p>\n<p><strong><span style=\"color: #808080;\">Como que voc\u00ea recuperou os caminhos dos backups?<\/span><\/strong><\/p>\n<p>Novamente aqui o trabalho foi facilitado pelo cliente que fez um form .Net que executa a query abaixo no MSDB e retorna as informa\u00e7\u00f5es dos backups da inst\u00e2ncia principal que est\u00e1 no Azure e faz a carga dessas informa\u00e7\u00f5es na Amazon, ou seja, um backup \u00e9 realizado no Azure, ele \u00e9 gravado na MSDB, de 30 em 30 segundos a aplica\u00e7\u00e3o valida se tem um backup novo, se tiver ele registra a informa\u00e7\u00e3o na Amazon. Tamb\u00e9m daria para fazer um script powershell para recuperar as informa\u00e7\u00f5es no Blob Storage, por\u00e9m foi mais simples utilizar a app que o cliente fez.<\/p>\n<pre class=\"theme:ssms2012 lang:tsql decode:true \">SELECT A.database_name,\r\n       A.backup_start_date,\r\n       A.backup_finish_date,\r\n       b.physical_device_name AS Diretorio,\r\n       A.type,\r\n       ROW_NUMBER() OVER (PARTITION BY A.database_name ORDER BY A.backup_start_date DESC) AS Ranking\r\nFROM msdb..backupset A\r\n    JOIN msdb..backupmediafamily b\r\n        ON b.media_set_id = A.media_set_id\r\nGROUP BY A.database_name,\r\n         A.backup_start_date,\r\n         b.physical_device_name,\r\n         A.backup_finish_date,\r\n         A.type;<\/pre>\n<p><a href=\"https:\/\/i0.wp.com\/www.tiagoneves.net\/blog\/wp-content\/uploads\/2018\/07\/Return_Query.png?ssl=1\" rel=\"lightbox[1422]\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-1428\" src=\"https:\/\/i0.wp.com\/www.tiagoneves.net\/blog\/wp-content\/uploads\/2018\/07\/Return_Query.png?resize=678%2C291&#038;ssl=1\" alt=\"\" width=\"678\" height=\"291\" srcset=\"https:\/\/i0.wp.com\/www.tiagoneves.net\/blog\/wp-content\/uploads\/2018\/07\/Return_Query.png?resize=300%2C129&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.tiagoneves.net\/blog\/wp-content\/uploads\/2018\/07\/Return_Query.png?resize=768%2C331&amp;ssl=1 768w\" sizes=\"auto, (max-width: 678px) 100vw, 678px\" \/><\/a><\/p>\n<p><strong><span style=\"color: #808080;\">E para fazer o restore como que voc\u00ea fez o controle do que j\u00e1 havia sido restaurado?<\/span><\/strong><\/p>\n<p>Para controlar a sequ\u00eancia l\u00f3gica dos backups que precisam ser restaurados e at\u00e9 mesmo para controlar a cadeia de log, eu criei uma tabela que chamo de &#8220;&#8221;, que extrai informa\u00e7\u00f5es da tabela de hist\u00f3rico de backups que foram realizados no Azure.<\/p>\n<pre class=\"theme:ssms2012 lang:tsql decode:true \">CREATE TABLE [dbo].[Controle_BKP](\r\n\t[ID] [int] IDENTITY(1,1) NOT NULL,\r\n\t[Nm_Database] [varchar](50) NULL,\r\n\t[Dt_Backup] [datetime] NULL,\r\n\t[Ds_Diretorio] [varchar](800) NULL,\r\n\t[Tipo_BKP] [char](1) NULL,\r\n\t[Fl_Restore] [bit] NULL DEFAULT ((0))\r\n) ON [PRIMARY]<\/pre>\n<p>Para extrair as informa\u00e7\u00f5es da tabela de hist\u00f3rico para tabela de controle, fiz uma procedure que pega o \u00faltimo backup full, o \u00faltimo diferencial (se utilizar) depois do full e os \u00faltimos backups de log depois do backup full ou do backup diferencial.<\/p>\n<pre class=\"theme:ssms2012 lang:tsql decode:true\">\/****** Object:  StoredProcedure [dbo].[stpCarga_Historico_Backup]    Script Date: 16\/07\/2018 20:39:09 ******\/\r\n\r\nCreate PROCEDURE [dbo].[stpCarga_Historico_Backup] @dbname sysname\r\nAS\r\nBEGIN\r\n\r\n---BKP FULL\r\n\tINSERT INTO Controle_BKP\r\n    (\r\n        Nm_Database,\r\n        Dt_Backup,\r\n        Ds_Diretorio,\r\n        Tipo_BKP,\r\n        Fl_Restore\r\n    )\r\n    SELECT A.database_name,\r\n           A.backup_start_date,\r\n           A.Diretorio,\r\n           A.type,\r\n           0\r\n\tFROM\r\n    (\r\n        SELECT A.database_name,\r\n               A.backup_start_date,\r\n               A.diretorio ,\r\n               A.type,\r\n               ROW_NUMBER() OVER (PARTITION BY A.database_name ORDER BY A.backup_start_date DESC) AS Ranking\r\n        FROM historico_backup A\r\n        WHERE A.type = ('D')\r\n             AND A.database_name = @dbname\r\n        GROUP BY A.database_name,\r\n                 A.backup_start_date,\r\n\t\t\t\t A.Diretorio,\r\n                 A.type\r\n    ) A\r\n        LEFT JOIN dbo.Controle_BKP cbd\r\n          ON cbd.Ds_Diretorio = A.Diretorio\r\n    WHERE A.Ranking = 1\r\n       AND cbd.Ds_Diretorio IS NULL;\r\n\r\n-- BKP DIF\r\n\r\n   INSERT INTO Controle_BKP\r\n    (\r\n        Nm_Database,\r\n        Dt_Backup,\r\n        Ds_Diretorio,\r\n        Tipo_BKP,\r\n        Fl_Restore\r\n    )\r\n    SELECT A.database_name,\r\n           A.backup_start_date,\r\n           Diretorio,\r\n           A.type,\r\n           0\r\n    FROM\r\n    (\r\n        SELECT A.database_name,\r\n               A.backup_start_date,\r\n               A.Diretorio,\r\n               A.type,\r\n               ROW_NUMBER() OVER (PARTITION BY A.database_name ORDER BY A.backup_start_date DESC) AS Ranking\r\n\t\tFROM historico_backup A\r\n        WHERE A.type = ('I')\r\n              AND A.database_name = @dbname\r\n\t\t\t     AND a.backup_start_date &gt;=\r\n          (\r\n              SELECT MAX(a.backup_finish_date)\r\n              FROM historico_backup A\r\n              WHERE a.type = ('D')\r\n                    AND a.database_name = @dbname\r\n              GROUP BY a.database_name,\r\n                       a.type)\r\n        GROUP BY A.database_name,\r\n                 A.backup_start_date,\r\n\t\t\t\t A.Diretorio,\r\n                 A.type\r\n    ) A\r\n        LEFT JOIN dbo.Controle_BKP cb\r\n            ON cb.Ds_Diretorio = A.Diretorio\r\n    WHERE A.Ranking = 1\r\n          AND cb.Ds_Diretorio IS NULL;\r\n\r\n -- BKP LOG\r\n\r\n    INSERT INTO Controle_BKP\r\n    (\r\n        Nm_Database,\r\n        Dt_Backup,\r\n        Ds_Diretorio,\r\n        Tipo_BKP,\r\n        Fl_Restore\r\n    )\r\n    SELECT a.database_name,\r\n           a.backup_start_date,\r\n           A.Diretorio,\r\n           a.type,\r\n           0\r\n     FROM historico_backup A\r\n        LEFT JOIN dbo.Controle_BKP cb\r\n            ON cb.Nm_Database = a.database_name\r\n               AND cb.Dt_Backup = a.backup_start_date\r\n    WHERE a.type = ('L')\r\n          AND a.database_name = @dbname\r\n          AND a.backup_start_date &gt;=\r\n          (\r\n              SELECT MAX(a.backup_finish_date)\r\n              FROM historico_backup A\r\n              WHERE a.type = ('D')\r\n                    AND a.database_name = @dbname\r\n              GROUP BY a.database_name,\r\n                       a.type\r\n          )\r\n          AND cb.Dt_Backup IS NULL\r\n    ORDER BY a.backup_start_date;\r\n\r\nend<\/pre>\n<p><strong>E agora, as tabelas de controle est\u00e3o criadas. Como fazer o restore?<\/strong><\/p>\n<p>O script abaixo \u00e9 uma procedure que faz o restore. Para facilitar a cria\u00e7\u00e3o dos bancos eu criei as mesmas estruturas de diret\u00f3rios do servidor de origem.<\/p>\n<p>Ao final de cada restore, a rotina faz um update na tabela de controle informando que aquele arquivo foi restaurado com sucesso.<\/p>\n<pre class=\"theme:ssms2012 lang:tsql decode:true \">Create PROCEDURE [dbo].[stpRestauraBancos]\r\n    @dbname sysname\r\n\r\nAS\r\nBEGIN\r\n\r\n    DECLARE @caminho VARCHAR(MAX),\r\n            @mdf VARCHAR(MAX),\r\n            @mdf_name sysname,\r\n            @ldf VARCHAR(MAX),\r\n            @ldf_name sysname;\r\n\r\n    SELECT @mdf = physical_name,\r\n           @mdf_name = mf.name\r\n    FROM master.sys.master_files mf\r\n        INNER JOIN master.sys.databases db\r\n            ON mf.database_id = db.database_id\r\n    WHERE mf.type = 0 \r\n          AND db.name = @dbname;\r\n \r\n   SELECT @ldf = physical_name,\r\n           @ldf_name = mf.name\r\n    FROM master.sys.master_files mf\r\n        INNER JOIN master.sys.databases db\r\n            ON mf.database_id = db.database_id\r\n    WHERE mf.type = 1 -- 1 = Log \r\n          AND db.name = @dbname;\r\n\r\n        --Restaurar backup full.\r\n        SET @caminho =\r\n        (\r\n            SELECT Ds_Diretorio\r\n            FROM restore_log.dbo.Controle_BKP\r\n            WHERE Tipo_BKP = 'D'\r\n                  AND Fl_Restore = 0\r\n                  AND Nm_Database = @dbname\r\n        );\r\n\r\n        IF @caminho IS NOT NULL     \r\n        BEGIN\r\n            RESTORE DATABASE @dbname\r\n            FROM URL = @caminho\r\n            WITH FILE = 1,\r\n                 MOVE @mdf_name\r\n                 TO @mdf,\r\n                 MOVE @ldf_name\r\n                 TO @ldf,\r\n                 NORECOVERY,\r\n                 NOUNLOAD,\r\n\t\t\t\t STATS = 10,\r\n                 REPLACE;\r\n\r\n            IF @@ERROR = 0\r\n            BEGIN\r\n                UPDATE restore_log.dbo.Controle_BKP\r\n                SET Fl_Restore = 1\r\n                WHERE Ds_Diretorio = @caminho;\r\n            END;\r\n\r\n            PRINT '&gt;&gt;&gt;Backup Full restaurado: ' + @caminho;\r\n\r\n        END;\r\n\r\n        --Restarurar backup diferencial.\r\n\r\n\t\tDECLARE cursor_BackupDiferencial CURSOR FOR\r\n        SELECT Ds_Diretorio\r\n        FROM restore_log.dbo.Controle_BKP\r\n        WHERE Tipo_BKP = 'I'\r\n              AND Fl_Restore = 0\r\n\t\t\t  AND Dt_Backup &lt;= (SELECT MIN(Dt_Backup) FROM restore_log.dbo.Controle_BKP WHERE Tipo_BKP = 'I'\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  AND Nm_Database = @dbname)\r\n              AND Nm_Database = @dbname;\r\n\r\n        OPEN cursor_BackupDiferencial;\r\n\r\n        FETCH NEXT FROM cursor_BackupDiferencial\r\n        INTO @caminho;\r\n\r\n        WHILE @@FETCH_STATUS = 0\r\n        BEGIN\r\n\r\n            RESTORE DATABASE @dbname\r\n            FROM URL = @caminho\r\n            WITH FILE = 1,\r\n                 NORECOVERY,\r\n\t\t\t\t NOUNLOAD,\r\n                 STATS = 10,\r\n                 REPLACE;\r\n\r\n            IF @@ERROR = 0\r\n            BEGIN\r\n                UPDATE restore_log.dbo.Controle_BKP\r\n                SET Fl_Restore = 1\r\n                WHERE Ds_Diretorio = @caminho;\r\n            END;\r\n\r\n            PRINT '&gt;&gt;&gt;Backup Diferencial restaurado: ' + @caminho;\r\n\r\n            FETCH NEXT FROM cursor_BackupDiferencial\r\n            INTO @caminho;\r\n        END;\r\n\r\n        CLOSE cursor_BackupDiferencial;\r\n        DEALLOCATE cursor_BackupDiferencial;\r\n\t\tend\r\n\t\t\r\n        --Restaurar backup de logs.\r\n        DECLARE cursor_backup_files CURSOR FOR\r\n        SELECT Ds_Diretorio\r\n        FROM restore_log.dbo.Controle_BKP\r\n        WHERE Tipo_BKP = 'L'\r\n              AND Fl_Restore = 0\r\n              AND Nm_Database = @dbname\r\n\t\t\t  ORDER BY Dt_Backup;\r\n\r\n        OPEN cursor_backup_files;\r\n\r\n        FETCH NEXT FROM cursor_backup_files\r\n        INTO @caminho;\r\n\r\n        WHILE @@FETCH_STATUS = 0\r\n        BEGIN\r\n\r\n            RESTORE LOG @dbname\r\n            FROM URL = @caminho\r\n            WITH FILE = 1,\r\n                 NORECOVERY,\r\n\t\t\t\t STATS = 10;\r\n\r\n            IF @@ERROR = 0\r\n            BEGIN\r\n                UPDATE restore_log.dbo.Controle_BKP\r\n                SET Fl_Restore = 1\r\n                WHERE Ds_Diretorio = @caminho;\r\n            END;\r\n\r\n            PRINT '&gt;&gt;&gt;Backup de Log restaurado: ' + @caminho;\r\n\r\n            FETCH NEXT FROM cursor_backup_files\r\n            INTO @caminho;\r\n\r\n        END\r\n\r\n        CLOSE cursor_backup_files;\r\n        DEALLOCATE cursor_backup_files;\r\n\r\nEND<\/pre>\n<p>Ap\u00f3s a cria\u00e7\u00e3o da procedure, eu criei um job que executa a cada 30 minutos. Isso ficou alinhado com o cliente que assumiu que poderia perder at\u00e9 30 minutos de dados.<\/p>\n<p>E assim o cliente ficou feliz por que agora tem uma r\u00e9plica do seu banco de dados SQL Server do Azure na Amazon.<\/p>\n<p>Bom pessoal por hoje \u00e9 isso.<\/p>\n<p>Um grande abra\u00e7o,<\/p>\n<p>Tiago Neves<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ol\u00e1 pessoal, tudo certo? No post de hoje vou compartilhar com voc\u00eas um caso que atendi em um de nossos clientes. O nosso cliente tem uma VM com o SQL Server no Azure e gostaria de ter um site de DR (disaster recovery) na Amazon. At\u00e9 ai tudo bem, voc\u00ea poderia falar &#8220;Tiago isso \u00e9 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1452,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"rop_custom_images_group":[],"rop_custom_messages_group":[],"rop_publish_now":"initial","rop_publish_now_accounts":{"twitter_91251433_91251433":""},"rop_publish_now_history":[],"rop_publish_now_status":"pending","_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_wpscppro_dont_share_socialmedia":false,"_wpscppro_custom_social_share_image":0,"_facebook_share_type":"","_twitter_share_type":"","_linkedin_share_type":"","_pinterest_share_type":"","_linkedin_share_type_page":"","_instagram_share_type":"","_medium_share_type":"","_threads_share_type":"","_google_business_share_type":"","_selected_social_profile":[],"_wpsp_enable_custom_social_template":false,"_wpsp_social_scheduling":{"enabled":false,"datetime":null,"platforms":[],"status":"template_only","dateOption":"today","timeOption":"now","customDays":"","customHours":"","customDate":"","customTime":"","schedulingType":"absolute"},"_wpsp_active_default_template":true},"categories":[212,2,5],"tags":[231,213,214,230,203,232,37,35],"class_list":["post-1422","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","category-casos-do-dia-a-dia","category-virtual-pass-br","tag-amazon","tag-azure","tag-backup","tag-cloud","tag-dba-vitoria","tag-replicacao","tag-restore","tag-sql-server"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.tiagoneves.net\/blog\/wp-content\/uploads\/2018\/07\/azure-aws-01-e1532521181505.png?fit=315%2C180&ssl=1","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p6eIyh-mW","jetpack-related-posts":[{"id":2414,"url":"https:\/\/www.tiagoneves.net\/blog\/sql-server-2016-esta-chegando-ao-fim-do-suporte-o-que-isso-significa-na-pratica\/","url_meta":{"origin":1422,"position":0},"title":"SQL Server 2016 est\u00e1 chegando ao fim do suporte: o que isso significa na pr\u00e1tica?","author":"tiagoneves","date":"27 de abril de 2026","format":false,"excerpt":"O SQL Server 2016 ter\u00e1 seu suporte estendido encerrado em 14 de julho de 2026, o que resultar\u00e1 na falta de atualiza\u00e7\u00f5es de seguran\u00e7a e suporte. Continuar usando essa vers\u00e3o traz riscos como vulnerabilidades e n\u00e3o conformidade regulat\u00f3ria. Planejar a migra\u00e7\u00e3o para vers\u00f5es mais recentes ou cloud deve ser prioridade\u2026","rel":"","context":"Em &quot;Seguran\u00e7a&quot;","block_context":{"text":"Seguran\u00e7a","link":"https:\/\/www.tiagoneves.net\/blog\/category\/seguranca\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.tiagoneves.net\/blog\/wp-content\/uploads\/2026\/04\/sql_server_2016_eos_v3.png?fit=772%2C702&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.tiagoneves.net\/blog\/wp-content\/uploads\/2026\/04\/sql_server_2016_eos_v3.png?fit=772%2C702&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.tiagoneves.net\/blog\/wp-content\/uploads\/2026\/04\/sql_server_2016_eos_v3.png?fit=772%2C702&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.tiagoneves.net\/blog\/wp-content\/uploads\/2026\/04\/sql_server_2016_eos_v3.png?fit=772%2C702&ssl=1&resize=700%2C400 2x"},"classes":[]}],"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tiagoneves.net\/blog\/wp-json\/wp\/v2\/posts\/1422","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tiagoneves.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tiagoneves.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tiagoneves.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tiagoneves.net\/blog\/wp-json\/wp\/v2\/comments?post=1422"}],"version-history":[{"count":21,"href":"https:\/\/www.tiagoneves.net\/blog\/wp-json\/wp\/v2\/posts\/1422\/revisions"}],"predecessor-version":[{"id":1464,"href":"https:\/\/www.tiagoneves.net\/blog\/wp-json\/wp\/v2\/posts\/1422\/revisions\/1464"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.tiagoneves.net\/blog\/wp-json\/wp\/v2\/media\/1452"}],"wp:attachment":[{"href":"https:\/\/www.tiagoneves.net\/blog\/wp-json\/wp\/v2\/media?parent=1422"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tiagoneves.net\/blog\/wp-json\/wp\/v2\/categories?post=1422"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tiagoneves.net\/blog\/wp-json\/wp\/v2\/tags?post=1422"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}