Database

Como identificar os bancos de dados com maior uso de CPU no SQL Server

Quando você possui um servidor de banco de dados que está tendo um alto consumo de CPU é necessário fazer um trabalho de investigação para identificar a origem desse consumo. Ou quando está querendo identificar quem são os maiores consumidores de recurso do seu servidor SQL. O SQL Server Management Studio (SSMS) não possui nenhum relatório específico para identificar isso, porém é possível fazer uma consulta SQL que traga a informação de uso de CPU para cada um dos seus bancos de dados.

Para isso execute a consulta:

SELECT T.[Database], T.[CPUTimeAsPercentage]
   FROM
    (SELECT 
        [Database],
        CONVERT (DECIMAL (6, 3), [CPUTimeInMiliSeconds] * 1.0 / 
        SUM ([CPUTimeInMiliSeconds]) OVER () * 100.0) AS [CPUTimeAsPercentage]
     FROM 
      (SELECT 
          dm_execplanattr.DatabaseID,
          DB_Name(dm_execplanattr.DatabaseID) AS [Database],
          SUM (dm_execquerystats.total_worker_time) AS CPUTimeInMiliSeconds
       FROM sys.dm_exec_query_stats dm_execquerystats
       CROSS APPLY 
        (SELECT 
            CONVERT (INT, value) AS [DatabaseID]
         FROM sys.dm_exec_plan_attributes(dm_execquerystats.plan_handle)
         WHERE attribute = N'dbid'
        ) dm_execplanattr
       GROUP BY dm_execplanattr.DatabaseID
      ) AS CPUPerDb
    )  AS T
ORDER BY T.[CPUTimeAsPercentage] DESC

O retorno da consulta será o nome do banco de dados seguido do seu consumo.

A consulta utiliza informação do plano de execução, ou seja, ela depende de informações de uso.

VM Resize

VM Resize – Runbook para redimensionar VMs no Azure

A ideia deste post é ensinar como redimensionar VMs do Azure via automação utilizando runbooks.

Infelizmente não é a realidade de todos conseguir trabalhar com um ambiente PaaS, que possuem diversos recursos para escalonamento horizontal, principalmente quando se fala de sistemas legados que utilizam tecnologias mais antigas ou até mesmo sistemas que não foram desenhados para nuvem. Neste cenário a solução é utilizar um ambiente IaaS utilizando VMs que na grande maioria das vezes se utiliza escalonamento vertical, ou seja, trabalha-se definindo o tamanho da VM (CPU e RAM). Essa VM acaba sendo dimensionada para aguentar a maior carga do sistema, e acaba ficando super dimensionada em determinados períodos, ou até mesmo ociosa.

Imagine o seguinte cenário, um sistema que possua um grande volume de uso durante o dia, porém de madrugada o acesso é muito baixo.

E como economizar dinheiro e fazer uso do que a nuvem nos oferece? Desligar a VM de madrugada? Desligar a VM poderia até ser uma solução para um cenário em que o sistema pudesse ficar fora do ar por algumas horas, que não é o cenário apresentado. Uma das possibilidades é criar um runbook que diminui o tamanho da VM de madrugada, e logo pela manhã aumenta o tamanho da VM retornando ao seu tamanho original. Desta forma é possível pagar menos pela VM enquanto ela permanecesse em tamanho reduzido.

Essa solução aplicada em um caso real trouxe uma economia de aproximadamente vinte porcento por mês.

A seguir será demonstrado como configurar a parte da automação para reduzir e aumentar o tamanho de uma VM de forma agendada no Azure.

Criando a conta de automação

O primeiro passo é criar uma conta de automação no painel do Azure. Para isso:

  • Clique em Criar um recurso;
  • Procure por “automação” na caixa de pesquisa;
  • Selecione o recurso de automação;
  • Clique em Criar;
  • Defina um nome para a conta de automação;
  • Defina um grupo de recurso;
  • Importante: A opção Criar conta Executar como do Azure deve estar como Sim, para que não seja necessário utilizar uma credencial do AD para execução do PowerShell;
  • Por fim clique em Criar.

Definindo variáveis

Após a conta de automação estar criada, abra o recurso e selecione a opção Variáveis no menu lateral.

Clique em Adicionar uma variável. Defina o nome da variável como AzureSubscriptionId do tipo Cadeia de caracteres e no valor defina a identificação da sua assinatura e clique em Criar.

Para localizar o ID da sua assinatura, pesquise na caixa de pesquisa por assinaturas.

Criando o runbook

Na conta de automação criada anteriormente selecione a opção Runbooks no menu lateral.

Escolha a opção Criar um runbook. Logo em seguida defina o nome do runbook e selecione o Tipo de runbook como PowerShell e clique em Criar.

Será exibida uma área para digitar o seu script. Utilize o seguinte PowerShell:

<#
.SYNOPSIS
  Conecta no Azure e escala a VM certicalmente.

.DESCRIPTION
  Este runbook conecta no Azure e escala a VM verticalmente. 

  CONFIGURAÇÕES NECESSÁRIAS
  1. Criar uma variável de automação chamada "AzureSubscriptionId" contendo o GUID da sua assinatura do Azure.  
  2. Criar uma credencial de automação chamada "AzureCredential" contendo as credenciais de um usuário do Azure AD com perfil de acesso. 
     (Se a conta for uma conta Microsoft não funciona, necessário criar um novo usuário)
  3. Se os módulos estiverem desatualizados dará erro ao redimensionar a VM para discos gerenciados. Irá dar um erro no arquivo vhd.

.PARAMETER ResourceGroupName
   Required 
   Nome do grupo de recurso.

.PARAMETER VmName
   Required 
   Nome da VM.

.PARAMETER VmSize
   Required 
   Tamanho da VM (Exemplo: Standard_DS1_V2, Standard_F4s).
#>

param (
    [parameter(Mandatory = $true)]
    [string]$ResourceGroupName,

    [parameter(Mandatory = $true)]
    [string]$VmName,

    [parameter(Mandatory = $true)]
    [string]$VmSize
)   
    $Conn = Get-AutomationConnection -Name AzureRunAsConnection
    $null = Add-AzureRmAccount -ServicePrincipal -TenantId $Conn.TenantId -ApplicationId $Conn.ApplicationId -CertificateThumbprint $Conn.CertificateThumbprint 
    
    $SubId = Get-AutomationVariable -Name 'AzureSubscriptionId'
    $null = Set-AzureRmContext -SubscriptionId $SubId -ErrorAction Stop
        
    try {
        $vm = Get-AzureRmVm -ResourceGroupName $ResourceGroupName -VMName $VmName -ErrorAction Stop
    } catch {
        Write-Error "Máquina virtual não encontrada"
        exit
    }
    $currentVMSize = $vm.HardwareProfile.vmSize
        
    Write-Output "`nMáquina virtual encontrada: $VmName"
    Write-Output "Tamanho atual: $currentVMSize"
    
    Write-Output "`nNovo tamanho será: $VmSize"
        
    $vm.HardwareProfile.VmSize = $VmSize
    Update-AzureRmVm -VM $vm -ResourceGroupName $ResourceGroupName

    Write-Output "`nVerificando o tamanho"
    
    $updatedVm = Get-AzureRmVm -ResourceGroupName $ResourceGroupName -VMName $VmName
    $updatedVMSize = $updatedVm.HardwareProfile.vmSize
    
    Write-Output "`nTamanho alterado para: $updatedVMSize"  

Clique em publicar e confirme a publicação clicando em Sim.

Você pode testar o seu runbook utilizando a opção Iniciar e logo em seguida em OK. Ao clicar em Iniciar ele irá solicitar os três parâmetros do PowerShell, sendo:

  • ResourceGroupName: nome do grupo de recurso da VM;
  • VMName: o nome da VM;
  • VMSize: o tamanho da VM.

Nesse momento, o seu runbook provavelmente irá falhar, e irá apresentar a mensagem “Vhd cannot be null”. Isso acontece porque ao criar a conta de automação os módulos não estão atualizados, e não suportam redimensionar VMs que possuem discos gerenciados. A solução é simples, basta atualizar os módulos.

Para resolver este problema, na conta de automação selecione a opção Módulos.

Se clicar em Atualizar módulos do Azure, você receberá uma mensagem pedindo para acessar um projeto do GitHub para atualizar os módulos. Mas existe um macete para atualizar todos os módulos pelo painel do Azure.

Escolha a opção Galeria de módulos, que fica logo abaixo dos Módulos. Pesquise pelo módulo AzureRM.Compute.

Selecione o módulo e utilize a opção Importar.

Na página a seguir marque a opção Eu concordo em atualizar todos os módulos do Azure e clique em OK.

O processo de atualização é um pouco demorado, leva alguns minutos. Se retornar na opção Módulos será exibida uma mensagem que os módulos estão em atualização. Assim que este processo terminar selecione novamente o runbook e faça o teste utilizando a opção Iniciar, e desta vez irá funcionar.

Agendando seu runbook

Agora que o seu runbook já funciona, falta apenas criar o agendamento para que seja executado num determinado horário. Selecione o seu runbook, e clique no menu Agendas.

Clique Adicionar um agendamento.

Selecione a opção Parâmetros e configurações de execução. Nesta opção defina o nome do grupo de recurso, o nome da VM, e o tamanho desejado da VM, assim como foi feito durante os testes, e clique em OK.

Selecione agora a opção de Agendar e em seguida Criar uma nova agenda.

Agora defina o horário em que o seu script será executado com os parâmetros definidos anteriormente e clique em Criar.

Nesse exemplo, foi configurado para que o runbook seja executado de forma recorrente todo dia às 0:00 com os parâmetros definidos anteriormente.

Retomando o caso de uso mencionado logo no início deste post, neste momento eu acabei de fazer um agendamento para que todo dia a minha VM às 0:00 seja redimensionada de tamanho, no caso para a configuração Standard_DS1_V2.

Agora preciso criar um novo agendamento, seguindo os mesmos passos, para que minha VM retorne ao tamanho original. Então defino nos parâmetros do novo agendamento o tamanho original da VM.

E no agendamento defino o horário que desejo que minha VM retorne ao tamanho original dela.

Pronto! O seu ambiente já está automatizado, e sua VM passará a ser redimensionada automaticamente de tamanho diariamente, fazendo com que pague menos pelo ambiente.

Um ponto muito importante que vale ressaltar é que esse processo de redimensionar a VM de tamanho fará com que a VM seja desligada e ligada logo em seguida, ou seja, ela ficará fora do ar por alguns minutos.

Azure Media Services

O Azure possui um serviço de streaming de vídeos chamado Azure Media Services. Além do streaming, ele possibilita fazer download progressivo e transmissões ao vivo. A comunicação com este serviço pode ser feita através de uma API REST ou através de SDKs disponíveis para algumas linguagens.

Eu fiz um pequeno exemplo de como consumir esta API utilizando o SDK disponível para C# e disponibilizei o código no github, no link abaixo:

https://github.com/rkiguti/azure.media.services

Neste exemplo, é feito o upload de um arquivo de vídeo (*.mp4) e outro de áudio (*.mp3), em seguida é criada uma tarefa para codificação dos arquivos para que possa ser transmitido via streaming, e por fim é feito a publicação destes arquivos. Neste mesmo projeto há uma aplicação web, que tem um player de exemplo consumindo uma URL de streaming do Azure Media Services.

Para que o exemplo execute, é necessário configurar no arquivo App.config as credenciais da sua conta no Azure, e no arquivo Program.cs alterar o local dos arquivos de vídeo e áudio que será feito o upload.

Alguns links que utilizei para montar o exemplo e configurar a conta no Azure:

https://docs.microsoft.com/pt-br/azure/media-services/media-services-dotnet-get-started

https://azure.microsoft.com/en-us/blog/azure-media-service-aad-auth-and-acs-deprecation/

Descobrir o nome da constraint default de uma coluna no SQL Server

Quando se cria uma coluna com valor default no SQL Server, e não se define o seu nome, o SQL Server cria uma constraint para o default com um nome aleatório. Porém, se você precisar alterar algum atributo desta coluna, o SQL Server não deixará efetuar a alteração enquanto a constraint existir.

Para descobrir o nome da constraint referente ao default associada a determinada coluna execute a seguinte consulta.

SELECT OBJECT_NAME(cdefault)
  FROM dbo.syscolumns
 WHERE id = OBJECT_ID('NOME_TABELA')
   AND name = 'NOME_CAMPO'

 

Database

Obter os comandos mais custosos no SQL Server

Neste post vou falar como obter os comandos mais custosos em um determinado servidor SQL Server.

Muitas vezes a baixa performance de uma aplicação está relacionada ao banco de dados. E isto ocorre porque as consultas enviadas para o banco de dados não estão otimizadas, ou estão retornando mais dados que deveriam, ou até mesmo há uma mesma consulta sendo executava muitas vezes desnecessariamente.

Para identificar essas consultas ruins, é possível executar a query abaixo, que retornará os 10 piores comandos executados no SQL Server. Lembrando que o comando leva em consideração as estatísticas, ou seja, o comando irá funcionar somente se o banco de dados estiver em uso.

SELECT TOP 10 SUBSTRING(qt.TEXT, (qs.statement_start_offset/2)+1,
((CASE qs.statement_end_offset
WHEN -1 THEN DATALENGTH(qt.TEXT)
ELSE qs.statement_end_offset
END - qs.statement_start_offset)/2)+1),
qs.execution_count,
qs.total_logical_reads, qs.last_logical_reads,
qs.total_logical_writes, qs.last_logical_writes,
qs.total_worker_time,
qs.last_worker_time,
qs.total_elapsed_time/1000000 total_elapsed_time_in_S,
qs.last_elapsed_time/1000000 last_elapsed_time_in_S,
qs.last_execution_time,
qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
ORDER BY qs.total_logical_reads DESC -- logical reads
-- ORDER BY qs.total_logical_writes DESC -- logical writes
-- ORDER BY qs.total_worker_time DESC -- CPU time

É possível também alterar a ordenação da consulta, retornando os comandos mais custosos em relação a leitura, escrita ou tempo de CPU.

Há outras formas de identificar gargalos na aplicação, mas essa é uma ótima opção para iniciar os trabalhos de otimização.

Novidades do C# 6.0 – Expression-bodied methods

Continuando a falar sobre as novidades do C# 6.0, disponível no Visual Studio 2015, é possível simplificar a escrita de métodos ou propriedades através do expression-bodied methods.

Para exemplificar, vou utilizar uma classe chamada Ponto com as propriedades X e Y, mais o método ToString, conforme código abaixo:

class Ponto
{
    public int X { get; set; }

    public int Y { get; set; }

    public override string ToString()
    {
        return $"Ponto ({X}, {Y})";
    }
}

Utilizando a nova sintaxe, é possível simplificar o método ToString em uma única linha:

class Ponto
{
    public int X { get; set; }

    public int Y { get; set; }

    public override string ToString() => $"Ponto ({X}, {Y})";
}

Esta mesma sintaxe pode ser utilizada para propriedades, vamos supor que eu tenha uma propriedade qualquer que retorne um valor:

class Ponto
{
    public int X { get; set; }

    public int Y { get; set; }

    public int propriedade 
    {
        get
        {
            return this.X * this.Y; 
        }
    }
}

Ela pode ser simplificada da seguinte forma:

class Ponto
{
    public int X { get; set; }

    public int Y { get; set; }

    public int propriedade => this.X * this.Y;
}

Observe que não é necessário informar o get neste caso, pois está implícito. Com esta sintaxe, não é possível ter o get e o set para a propriedade.

Para quem tiver interesse em conhecer todas as novidades do C# 6.0 acesse o link.

Remover workspace do servidor TFS

A ideia deste post é ensinar como remover um workspace do Team Foundation Server (TFS) remoto. E pra começar vou explicar o problema que já aconteceu algumas vezes na empresa que trabalho.

Tudo começa com um desenvolver que se desliga da empresa que utilizava o TFS e o Visual Studio. Ou seja, ele possuía na sua máquina um workspace mapeado para alguma coleção do TFS. Daí a máquina deste funcionário é formatada, é mantido o mesmo nome da máquina, porém outro usuário passa a utilizá-la. No momento que o novo desenvolvedor vai tentar mapear a coleção para a sua máquina recebe uma mensagem de erro informando que já há outro workspace mapeado para aquela máquina.

Isso ocorre porque sempre que criamos um workspace local e mapeamos para uma coleção do TFS, isso fica registrado no servidor. E para resolver este problema é necessário excluir esse workspace do servidor do TFS. E na maioria das vezes que isto ocorre, o usuário antigo nem existe mais na rede, dificultando resolver o problema.

Para excluir o workspace remoto, basta abrir o prompt de comando do Visual Studio e digitar o seguinte comando:

tf workspace /server:<SERVIDOR TFS> /delete <WORKSPACE>

Exemplo do comando:

tf workspace /server:http://servidor:8080/tfs/ /delete PC01;DOMINIO\usuario

Há outro comando útil que lista todos os workspaces do servidor TFS:

tf workspaces /server:<SERVIDOR TFS> /owner:*

Se o mapeamento estiver a nível de coleção, no endereço do servidor informe o caminho até o nível da coleção. Por exemplo:

tf workspaces /server:http://servidor:8080/tfs/Colecao /owner:*

Quando se trata de apenas um workspace o problema é resolvido rapidamente utilizando um único comando. Porém, quando se trata de vários recomendo o uso de alguma ferramenta para facilitar o trabalho. Uma destas ferramentas é o Team Foundation Sidekicks. Com ela é possível ver todos os workspaces existentes e excluí-los, além de realizar outras operações administrativas.

Novidades do C# 6.0 – Operador condicional nulo

No post anterior comentei sobre uma das novidades do C# 6.0, a interpolação de strings.

Agora neste post vou comentar sobre o operador condicional nulo, que particularmente, dentre as novidades, foi a que mais me agradou.

Com certeza você já teve ter passado por uma situação na qual precisasse testar se determinado objeto é nulo para então acessar uma propriedade ou método. Pois se acessarmos uma propriedade ou método de um objeto nulo ocorrerá uma exceção de referência nula.

Para exemplificar, vamos supor que eu possua uma classe Ponto com as propriedades X e Y. E esta mesma classe possua um método estático para instanciar um objeto do tipo Ponto a partir de um objeto Json, conforme código abaixo:

class Ponto
{
    public int X { get; set; }

    public int Y { get; set; }

    public static Ponto FromJson(JObject json)
    {
        if (json != null &&
            json["X"] != null &&
            json["X"].Type == JTokenType.Integer &&
            json["Y"] != null &&
            json["y"].Type == JTokenType.Integer)
        {
            return new Ponto() { X = (int)json["X"], Y = (int)json["Y"] };
        }

        return null;
    }
}

Agora, para simplificar este código vamos utilizar o operador condicional nulo, e vamos reescrever novamente a classe:

class Ponto
{
    public int X { get; set; }

    public int Y { get; set; }

    public static Ponto FromJson(JObject json)
    {
        if (json != null &&
            json["X"]?.Type == JTokenType.Integer &&
            json["Y"]?.Type == JTokenType.Integer)
        {
            return new Ponto() { X = (int)json["X"], Y = (int)json["Y"] };
        }

        return null;
    }
}

Perceba que foi utilizado o caractere ? no código fonte. Isto significa que a propriedade Type somente será acessada se o objeto for diferente de nulo, evitando que ocorra uma exceção. Ainda podemos diminuir mais um pouco o código:

class Ponto
{
    public int X { get; set; }

    public int Y { get; set; }

    public static Ponto FromJson(JObject json)
    {
        if (json?["X"]?.Type == JTokenType.Integer &&
            json?["Y"]?.Type == JTokenType.Integer)
        {
            return new Ponto() { X = (int)json["X"], Y = (int)json["Y"] };
        }

        return null;
    }
}

Agora ele somente acessará o “X” e o “Y” se o objeto json recebido por parâmetro não for nulo.

Outro uso que podemos dar para este operador é para quando estamos trabalhando com eventos. Se você já trabalhou com eventos provavelmente já deve ter escrito o seguinte trecho de código:

if (OnChanged != null)
{
    OnChanged(this, args);
}

Utilizando o operador condicional nulo, podemos reescrever este mesmo código da seguinte forma:

OnChanged?.Invoke(this, args);

O uso deste operador, quando bem utilizado, pode evitar vários erros de referência, além de reduzir o código fonte.

Para quem tiver interesse em conhecer todas as novidades do C# 6.0 acesse o link.

Novidades do C# 6.0 – Interpolação de strings

O Visual Studio 2015, lançado oficialmente no dia 20 de julho de 2015, trouxe algumas novidades sendo uma delas o C# 6.0.

Não foram grandes mudanças, mas surgiram recursos que podem aumentar a produtividade do programador. Dentre as novidades uma delas é a interpolação de strings.

Para exemplificar, vamos considerar o seguinte cenário. Digamos que você precise criar uma classe chamada Ponto com as propriedades X e Y. Esta classe possuirá o método ToString retornando o texto “Ponto (X, Y)”, sendo X e Y o valor das propriedades. Para fazer isso, no método ToString, você usaria o string.Format para fazer a concatenação do meu texto:

class Ponto
{
    public int X { get; set; }

    public int Y { get; set; }

    public override string ToString()
    {
        return string.Format("Ponto ({0}, {1})", X, Y);
    }
}

Com o C# 6.0 podemos escrever este mesmo trecho de código de uma forma mais simples, utilizando a interpolação de strings:

class Ponto
{
    public int X { get; set; }

    public int Y { get; set; }

    public override string ToString()
    {
        return $"Ponto ({X}, {Y})";
    }
}

Observe que ao invés de utilizar um número dentro das chaves, como era feito com o string.Format, podemos colocar diretamente a variável dentro das chaves. Para isto basta colocar no início da string o caractere $.

Para quem tiver interesse em conhecer todas as novidades do C# 6.0 acesse o link.