Dividir licenças entre DBAccess

O ambiente ideal para testes na empresa deve ser totalmente apartado, inclusive com DBAccess próprio. Para apontar dois DBAccess para um mesmo License Server é preciso definir quantas licenças cada um irá consumir pois, senão, o primeiro que se conectar ganha todas e o outro fica apenas com as 2 de demonstração. Isso é bem ruim quando o primeiro a se conectar é o de testes, ficamos sem licenças suficientes para a produção.

A solução é bem simples. Após instalar e configurar os dois DBAccess, faça a divisão através da cláusula LicenseLimit no DBAccess.ini. Os dois DBAccess devem ter essa configuração, senão não adianta.

Digamos que você tenha 50 licenças Top Connect, veja o exemplo de configuração abaixo para que reservemos 15 licenças para teste e o restante (35 licenças) para a produção.

DBAccess de Produção:

[General]
LicenseServer=10.20.20.28
LicensePort=5555
ByYouProc=0
...
LicenseLimit=35 <-- Olha ela aqui

DBAccess de Teste:

[General]
LicenseServer=10.20.20.28
LicensePort=5555
ByYouProc=0
...
LicenseLimit=15 <-- Olha ela aqui

IMPORTANTE: após configurar, desligue os dois DBAccess e inicie-os novamente.

Anúncios

Pictures (máscaras) de campos

As máscaras começam sempre com @

Use @R para gravar apenas números (excluir caracteres ex. ponto, vírgula, barras) no banco.

Exemplo para um campo de CPF:

@R 999.999.999-99 // Onde 9 significa qualquer caractere numérico.

Segue a tabela com todos os parâmetros possíveis (retirada do TDN):

Caractere Descrição

A

Permite somente caracteres  alfa.

N

Permite somente caracteres  alfa e número.

X

Permite qualquer caractere

9

Permite dígitos de qualquer tipo incluído sinal

#

Permite dígitos, sinais e espaços para qualquer tipo de dado

L

Permite apenas Y,N, T e F

Y

Permite apenas Y,N

!

Converte caracteres alfa em maiúscula

$

Exibe o sinal de dólar

.

Exibe um ponto decimal

,

Exibe uma virgula

R

Insere caracteres  mais não salva no campo de dado.

Para campos numéricos que contenham decimal, é obrigatório o uso do @E seguido da máscara com pontos e vírgulas invertidos (padrão americano), exemplo:

@E 99,999,999.99 // os pontos e as vírgulas serão invertidos na visualização

Os separadores de milhar são opcionais. E lembre-se de casar o número de caracteres numéricos da máscara com o tamanho real do campo quando estiver criando ou alterando no configurador.

 

Informações retiradas do TDN: https://goo.gl/EPs2Ro

Usando TCLink para conectar a outra base de dados

php-db-connection

Olá meus amigos! Andei um pouco sumido, mas vou me esforçar em continuar postando conteúdo por aqui. Vamos falar de conexão com outros bancos de dados de dentro do Protheus.

Com as funções AdvConnection(), TCLink() e TcSetConn() podemos nos conectar a outras bases de dados através do DBAccess (TopConnect). Lembrando que primeiramente temos que seguir a configuração padrão que é criar a conexão ODBC no servidor onde está instalado o DBAccess e depois configurar no próprio DBMonitor como já fazemos com a base Protheus.

No nosso fonte, bastará alternar entre os bancos de dados para realizar consultas e comandos SQLs. Veja abaixo um exemplo simples para se conectar a um banco que chamamos de GRUPOBI onde o DBAccess se encontra no mesmo servidor da aplicação escutando na porta 7890.

Local cConexao    := SuperGetMV("MV_XXCON01", .F., "MSSQL/GRUPOBI")
Local cServerAddr := SuperGetMV("MV_XXCON02", .F., "localhost")
Local nPort       := Val(SuperGetMV("MV_XXCON03", .F., "7890"))

If Type("_nTopProtheus") == "U"

    Public _nTopProtheus

    _nTopProtheus := AdvConnection() // obtém o ID da conexão atual

EndIf

If Type("_nTopGrupoBI") == "U"

    Public _nTopGrupoBI

    MsgRun("Conectando a Grupo BI...","Conexão",;
        {|| _nTopGrupoBI := TcLink(cConexao,cServerAddr,nPort) })

    If _nTopGrupoBI < 0

        MsgAlert("Não foi possível se conectar com Grupo BI. "+;
                 "Essa falha pode ocorrer devido ao número de licenças excedidas. "+;
                 "Tente mais tarde ou contate o administrador do sistema.")

        Return .F.

    EndIf

EndIf

TcSetConn(_nTopGrupoBI) // Utilize essa função para alternar entre as conexões

Você precisará de permissão para criação de tabelas no banco, pois o Protheus criará automaticamente nesta base as seguintes tabelas de controle do DBAccess: TOP_PARAM, TOP_SP, TOP_VIRTUALIDX, TOP_FIELD e TOP_IDXSTATS.

Vejam mais informações no TDN: http://tdn.totvs.com/display/tec/TCSetConn

Problema ao restaurar backup no SQL Server

Algumas vezes pode ocorrer um problema muito chato ao restaurar um backup no SQL Server. É quando, após a restauração, o status do banco de dados permanece (restaurando) ou (restoring) e o SQL Server não permite nenhuma operação nessa base. Pesquisei na internet e descobri que o problema pode ocorrer no término da criação do arquivo de log. É um bug, mas a restauração foi bem sucedida. Encontrei uma solução extremamente simples para desbloquear o banco de dados. Acesse o Management Studio, conecte ao SQL Server, e execute o seguinte comando SQL:

RESTORE DATABASE NOME_DO_BANCO WITH RECOVERY

Pronto. Problema solucionado.

Limite de Memória no SQL Server

Adicionalmente ao post que eu fiz sobre Configuração de Balance no Protheus gostaria também de compartilhar uma configuração muito simples e que pode salvar servidores que estão à beira de um colapso, especialmente quando as aplicações do Protheus e o SQL Server rodam na mesma máquina. Essa situação (aplicações e banco no mesmo servidor) não é muito recomendada quando a empresa começa a exigir mais do sistema (a partir de 30 usuários simultâneos; ou quando se utiliza rotinas de processamento com certa frequência). Mas sabemos que nem todos possuem estrutura ($$$) suficiente para um dimensionamento ideal. Dessa forma, travamentos no sistema podem ser resolvidos com o Balance que expliquei anteriormente. Mas a lentidão ainda existirá. Resolvê-la completamente é outra história. Exige realmente um correto dimensionamento dos servidores, de preferência feito por um Analista de Infra e um bom DBA (eu não sou nem um nem outro!).

No entanto, podemos reduzir bastante a lentidão e praticamente nos livrar de travamentos no servidor por estouro de memória. Sabemos que o Windows Server não faz um gerenciamento de memória perfeito, portanto quando falei sobre o Balance expliquei que o ideal é que os appservers do Protheus não trabalhem com mais de 1 GB de memória cada. Acompanhando esse raciocínio, devemos então entender que o servidor precisa ter disponível esse 1 GB de memória RAM para cada appserver que configuramos. Quando temos uma demanda de 20 a 40 usuários, o SQL Server roda muito bem com 2 GB de RAM dedicados. Mas no padrão, o SQL Server utiliza TODA a memória disponível do sistema, e isso não é nada bom, pois o Windows Server frequentemente se enrola. Precisamos resolver isso! Então devemos definir no SQL Server um limite máximo de uso de memória.

(1) No Management Studio, clique com o botão direito no servidor conectado.

(2) Em seguida, clique em Propriedades ou Properties.

memsql_1

 

(3) Acesse a página Memória ou Memory.

(4) Edite o campo Maximum server memory ou Memória máxima do servidor.

memsql_2

Pronto. Ao confirmar essa tela, imediatamente você poderá ver no monitor de recursos ou gerenciador de tarefas, que o SQL Server agora ocupará no máximo o número que você determinou. Lembrando que você somente conseguirá editar essa configuração se for o administrador do SQL Server.

Assim, se configuramos um balance com 1 master e 3 slaves, por exemplo, ter um servidor com 8 GB de memória RAM é suficiente, pois deixamos 2 GB para o próprio Windows Server que trabalhará com uma folga + 4 GB para os appservers + 2 GB para o SQL Server.

Mais uma vez quero deixar claro de que não sou um expert em Infra tão menos um DBA. Minhas dicas são com base na minha experiência no mercado atendendo empresas de médio e grande porte como consultor de negócios, analista e programador, onde eventualmente me deparo com problemas no servidor e preciso dar solução imediata. Então, por favor, não considerem as minhas dicas como a última verdade!

Mas elas funcionam 😉

Transferir registros via SQL

Frequentemente precisamos importar dados de uma tabela criando registros em outra tabela (ou na mesma). Acontece que quando temos formatos diferentes, pela PSDU fica impossível. Então é necessário criar uma rotina para isso, ou então utilizar um artifício pelo SQL Management mesmo.

Segue um exemplo de query que cria uma outra query para, por exemplo, copiar as Previsões de Venda (tabela SC4) para o Plano Mestre de Produção (tabela SHC) de uma determinado período. Esse exemplo é apenas para ilustrar, pois esse artifício pode ser usado para qualquer outra coisa e inclusive pode ser aperfeiçoado dependendo da necessidade:

SELECT
 'INSERT INTO SHC010 (HC_FILIAL,HC_PRODUTO,HC_DATA,HC_QUANT,HC_DOC,R_E_C_N_O_) SELECT ''01'','''+
 C4_PRODUTO+''','''+
 C4_DATA+''','+
 STR(C4_QUANT)+','''+
 C4_DOC+''','+
 '(SELECT CASE WHEN MAX(R_E_C_N_O_) IS NULL THEN 1 ELSE MAX(R_E_C_N_O_)+1 END FROM SHC010)' SQLSTR
FROM
 SC4010
WHERE
 D_E_L_E_T_ = ' '
 AND C4_DATA BETWEEN '20141027' AND '20141031'
ORDER BY
 C4_DATA,
 C4_PRODUTO,
 C4_LOCAL

Perceba que para o R_E_C_N_O_ utilizamos uma subquery que recalcula em cada inserção. Qual é o resultado dessa query? Configure no Management Studio no menu Query / Results to / Results to Text e terá o resultado como texto simples:

SQLSTR
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
INSERT INTO SHC010 (HC_FILIAL,HC_PRODUTO,HC_DATA,HC_QUANT,HC_DOC,R_E_C_N_O_) SELECT '01','05010 ','20141027', 100,'271014 ',(SELECT CASE WHEN MAX(R_E_C_N_O_) IS NULL THEN 1 ELSE MAX(R_E_C_N_O_)+1 END FROM SHC010)

...

INSERT INTO SHC010 (HC_FILIAL,HC_PRODUTO,HC_DATA,HC_QUANT,HC_DOC,R_E_C_N_O_) SELECT '01','05011 ','20141027', 420,'271014 ',(SELECT CASE WHEN MAX(R_E_C_N_O_) IS NULL THEN 1 ELSE MAX(R_E_C_N_O_)+1 END FROM SHC010)

...

INSERT INTO SHC010 (HC_FILIAL,HC_PRODUTO,HC_DATA,HC_QUANT,HC_DOC,R_E_C_N_O_) SELECT '01','05040 ','20141027', 130,'271014 ',(SELECT CASE WHEN MAX(R_E_C_N_O_) IS NULL THEN 1 ELSE MAX(R_E_C_N_O_)+1 END FROM SHC010)