Dec 15, 2010

¡No me puedo conectar remotamente a sql server 2008! ¿Qué sucede? ¿Tendrá algo que ver que he Instalado SQL SERVER con un nombre de Instancia que yo he definido y nó el por defecto?

www.felipedonoso.cl
felipe@felipedonoso.cl
RC6016
1NF3RNU5



Si les sucede que después de haber Instalado SQL Server 2008 o 2005, y desean conectarse remotamente desde algún cliente, obtienen el error:

"A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 0 - A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.) (Microsoft SQL Server, Error: 10060)"

¡¡¡¡No se desesperen por el error anterior!!!!









 Esto puede tener solución.


Lo que deberían hacer es habilitar las respectivas reglas del firewall en el sistema Operativo. Windows Server 2008 es algo más complicado en este sentido, y la administración del firewall cambió algo con respecto a windows server 2003. Por defecto lo que deberiamos hacer es habilitar las reglas INBOUND y OUTBOUND, para los puertos 1433 del servicio SQL SERVER y el 1434 para el servicio SQL BROWSER que se encarga de mostrar en nuestro mangement studio las otras instancias de sql server presentes en la red.

Pero puede suceder el caso de que aún así habilitando dichas reglas (excepciones mejor dicho) en el firewall la conexión aún no funciona y volvemos a tener el mismo error. ¿Qué puede suceder? La respuesta puede ser esta: Si han instalado la base de datos SQL Server con un nombre de Instancia propio definido por ustedes, se habilitará automáticamente el puerto dinámico de SQL SERVER, es decir la Instancia recibirá peticiones a través de cualquier puerto que probablemente no sea el 1433. Por default sólo las Instancias nombradas pueden usar puerto dinámico.

Por ejemplo si revisaran los archivos log de SQL SERVER se darían cuenta que en ellos aparece el mensaje en dónde se indica el puerto a través del cual se están recibiendo peticiones, algo así:

SQL server listening on ip_servidor:puerto

Una manera rápida de revisar los archivos de log y buscar el puerto de sql server actual puede ser utilizar el siguiente procedimiento:

Use master 
Go 
exec Xp_readerrorlog

Ejecutando dicho procedimiento se percatarán de que no están usando el puerto por defecto 1433. Recuerden como mencioné anteriormente que esto sucede sólo para las Instancias nombradas. Para solucionar esto lo que debemos hacer es reasignar el puerto por defecto a la Instancia de SQL Server, que es el 1433.

¿Cómo se logra hacer esto?


Pues bien es bastante sencillo. Primero procedemos a ingresar al SQL SERVER Configuration Manager (que esta dentro del grupo de programas de SQL SERVER), luego dentro de la pestaña SQL Server Network Configuration, seleccionamos Protocols for Instancia (En este caso mi instancia se llama MIRROR). Dentro de esa ventana debemos seleccionar las propiedades del elemento TCP/IP (click secundario). En la nueva ventana seleccionamos la pestaña IP Addresses, y buscamos las propiedades TCP Dynamic ports y TCP Port. En el caso de TCP Dynamic ports procedemos a dejarlo en blanco, y para TCP Port procedemos asignar el 1433 o el que estimemos conveniente, luego reinicien la Instancia. Dejo una imágen como referencia.



Para revisar nuestra configuración podemos ver el puerto que tenemos asignado para sql server luego de reiniciar esta instancia y revisando los logs con el procedimiento exec Xp_readerrorlog, o también revisando la siguiente clave de registro windows (regedit)

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\\MSSQLServer\SuperSocketNetLib\Tcp\IPAll


(la x corresponde a su versión de SQL SERVER, por ejemplo si es la versión 2008 debería decir 10)


Eso sería todo lo que es necesario ejecutar.
Mis saludos.






Dec 9, 2010

Soporte Oracle para bases de datos bajo ambientes VMware

He encontrado una interesante noticia para aquellas empresas que les gusta Oracle y la virtualización por Vmware. Oracle soportará (distinto de certificar, en eso Oracle es explícito) que su base de datos corra bajo ambientes vmware. Esto quiere decir que Oracle aceptara recibir solicitudes de soporte para resolver issues y permitir aplicar los respectivos workaround en el ambiente de base de datos. Eso si se menciona que para los ambientes RAC sólo estará el soporte disponible desde las versiones 10.2.0.2 en adelante. Ahora bien en la nota metalink respectiva mencionan claramente que si la solución o aplicación de cierto parche, no soluciona el problema en el ambiente virtualizado pero que si lo hace en el mismo sistema operativo de manera nativa (sin virtualizar) el Cliente deberá tomar contacto con el Soporte de VMWARE. Interesante noticia.

Les adjunto la nota metalink respectiva.
Support Position for Oracle Products Running on VMWare Virtualized Environments [ID 249212.1]




Link directo: https://support.oracle.com/CSP/ui/flash.html#tab=Dashboard(page=Dashboard&id=ghhq8ziz()),(page=KBNavigator&id=ghhqcdga(userQuery=origin%20ora%2054&filterSource=KB&&searchControl=1146&searchMode=1145&viewingMode=1141)),(page=KBNavigator&id=ghhvdt5c(from=favorites&&viewingMode=1143))

Nov 21, 2010

10 cosas que seguramente te habran pasado en Linux

Una noticia muy chistosa y entretenida acerca de cosas que nos han pasado  a quienes nos gusta este sistema operativo:

http://paraisolinux.com/10-cosas-que-seguramente-te-habran-pasado-en-linux/

La recomiendo muy entretenida.

Nov 13, 2010

Instalando office 2007 o 2010 obteniendo el error "The Windows Installer service cannot update one or more protected Windows files."

Estaba hace poco intentado instalar office 2007 en mi windows xp y obtuve el error "The Windows Installer service cannot update one or more protected Windows files." a los pocos segundos de empezar a instalar. Probé instalando office 2010 y me pasó exactamente lo mismo. Buscando en la Web encontré la siguiente solución que aplica muy bien y soluciona el problema:
http://nctritech.wordpress.com/2010/01/05/office-2007-the-windows-installer-service-cannot-update-one-or-more-protected-windows-files/

saludos.

Oct 29, 2010

Respaldar o visualizar privilegios sobre objetos en SQL Server

¿Se han preguntado como en SQL Server yo puedo averiguar que privilegios existen en mi base de datos y que para que usuarios están siendo estos otorgados? Bueno, existe un método para averiguar esto, que también a su vez puede servir como método de Backup & Recovery. Lo he encontrado desde el el sitio web http://www.mssqltips.com.

Que un DBA posea a su alcance información de esta naturaleza puede ser de gran utilidad frente a determinadas circunstancias. En Oracle sabemos que existen vistas que entregan esta información como DBA_PROFILES, DBA_ROLES,etc. ¿Pero que hay para SQL Server? La Receta mágica es:


El procedimiento almacenado: sp_helprotect.

Este procedimiento almacenado entrega información de privilegios asignados sobre objetos de base de datos. He aquí un ejemplo de la información que entrega:

(Naturalmente ocupamos el usuario SA)

EXEC master.dbo.sp_helprotect;



Aún así para obtener un script más automatizado que nos entregue un procedimiento con todas las sentencias grant de nuestra base de datos, podemos utilizar las siguientes funciones para obtener un listado de comandos listos para usar:

-- Temporary table to hold results from sp_helprotect

drop table #TempPerms

go

CREATE TABLE #TempPerms (

[Owner] sysname NULL,

[Object] sysname NULL,

[Grantee] sysname NULL,

[Grantor] sysname NULL,

[ProtectType] NVARCHAR(9) NULL,

[Action] NVARCHAR(100) NULL,

[Column] NVARCHAR(300) NULL,

[WithGrant] VARCHAR(18) NULL DEFAULT ''

);

-- Let sp_helprotect do the work for us

INSERT INTO #TempPerms

([Owner], [Object], [Grantee], [Grantor], [ProtectType], [Action], [Column])

EXEC master.dbo.sp_helprotect;


-- actualizamos por si acaso la columna ProtectType

-- en el caso de existieran valores 'Grant_WGO'

-- lo que quiere decir que se otorgaron privilegios

-- con permisos de otorgamiento hacia otros usuarios

UPDATE #TempPerms

SET [ProtectType] = 'Grant ', [WithGrant] = ' WITH GRANT OPTION'

WHERE [ProtectType] = 'Grant_WGO';


-- Build and output the permissions

SELECT

CASE [Owner]

WHEN '.' THEN ProtectType + ' ' + [Action] + ' TO [' + [Grantee] + ']' + [WithGrant] + ';'

ELSE CASE [Column]

WHEN '(All+New)' THEN ProtectType + ' ' + [Action] + ' ON [' + [Owner] + '].[' + [Object] + '] TO [' + Grantee + ']' + [WithGrant] + ';'

WHEN '(All)' THEN ProtectType + ' ' + [Action] + ' ON [' + [Owner] + '].[' + [Object] + '] TO [' + Grantee + ']' + [WithGrant] + ';'

WHEN '.' THEN ProtectType + ' ' + [Action] + ' ON [' + [Owner] + '].[' + [Object] + '] TO [' + Grantee + ']' + [WithGrant] + ';'

ELSE ProtectType + ' ' + [Action] + ' ON [' + [Owner] + '].[' + [Object] + '] ([' + [Column] + ']) TO [' + Grantee + ']' + [WithGrant] + ';'

END

END AS 'Permissions'

FROM #TempPerms;

Al ejecutar la consulta verán que el resultado será el siguiente. (les sugiero presionar [CTRL+T] para obtener los resultados en modo texto más rápido.

Grant Execute ON [dbo].[fn_MSgensqescstr] TO [public];

Grant Execute ON [dbo].[fn_MSsharedversion] TO [public];

Grant Execute ON [dbo].[fn_sqlvarbasetostr] TO [public];

Grant Execute ON [dbo].[fn_varbintohexstr] TO [public];

Grant Execute ON [dbo].[fn_varbintohexsubstring] TO [public];

Grant Execute ON [dbo].[MS_sqlctrs_users] TO [public];

Esto funciona a la perfección en SQLServer2000 hacia atrás. Ahora para SQL Server 2005 y superior se tiene que realizar una consulta sobre las tablas sys.database_permissions, sys.database_principals y sys.objects. La query quedaría mas o menos así:

SELECT CASE dperms.state_desc

WHEN 'GRANT_WITH_GRANT_OPTION' THEN 'GRANT'

ELSE state_desc

END

+ ' ' + permission_name + ' ON ' +

CASE dperms.class

WHEN 0 THEN 'DATABASE::[' + DB_NAME() + ']'

WHEN 1 THEN

CASE dperms.minor_id

WHEN 0 THEN 'OBJECT::[' + sch.[name] + '].[' + obj.[name] + ']'

ELSE 'OBJECT::[' + sch.[name] + '].[' + obj.[name] + '] ([' + col.[name] + '])'

END

WHEN 3 THEN 'SCHEMA::[' + SCHEMA_NAME(major_id) + ']'

WHEN 4 THEN 'USER::[' + USER_NAME(major_id) + ']'

WHEN 24 THEN 'SYMMETRIC KEY::[' + symm.[name] + ']'

WHEN 25 THEN 'CERTIFICATE::[' + certs.[name] + ']'

WHEN 26 THEN 'ASYMMETRIC KEY::[' + asymm.[name] +']'

END

+ ' TO [' + dprins.[name] + ']' +

CASE dperms.state_desc

WHEN 'GRANT_WITH_GRANT_OPTION' THEN ' WITH GRANT OPTION;'

ELSE ';'

END COLLATE database_default AS 'Permissions'

FROM sys.database_permissions dperms

INNER JOIN sys.database_principals dprins

ON dperms.grantee_principal_id = dprins.principal_id

LEFT JOIN sys.columns col

ON dperms.major_id = col.object_id AND dperms.minor_id = col.column_id

LEFT JOIN sys.objects obj

ON dperms.major_id = obj.object_id

LEFT JOIN sys.schemas sch

ON obj.schema_id = sch.schema_id

LEFT JOIN sys.asymmetric_keys asymm

ON dperms.major_id = asymm.asymmetric_key_id

LEFT JOIN sys.symmetric_keys symm

ON dperms.major_id = symm.symmetric_key_id

LEFT JOIN sys.certificates certs

ON dperms.major_id = certs.certificate_id

WHERE dperms.type <> 'CO'

AND dperms.major_id > 0;


Eso es todo.

Aquí la fuente origina la Fuente Original:

http://www.mssqltips.com/tip.asp?tip=2142

Como optimizar consultas en Oracle con el parámetro optimizer_index_cost_adj

Es muy común que los DBAs traten dentro de los ambientes OLTP evitar este tipo de accesos a los datos. Sabemos que este acceso es lento para tablas grandes, pero también sabemos que es muy usado en tablas pequeñas. Veamos como podemos sacar provecho de la eliminación o uso del no muy bien ponderado full table scan.

Vamos a empezar a ver algún ejemplo práctico: Vamos a crear una tabla mas o menos masiva a partir de otra ya existente:

[oracle@antares ~]$ sqlplus “/as sysdba”

SQL*Plus: Release 9.2.0.8.0 – Production on Tue Mar 3 17:06:31 2009

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Connected to:
Oracle9i Release 9.2.0.8.0 – Production
JServer Release 9.2.0.8.0 – Production

SQL> create table tabla_test as select * from obj$;

Table created.

SQL> select count(*) from tabla_test;

COUNT(*)
———-
66084

SQL>

Una vez que tengamos creada nuestra tabla, vamos a realizar una simple consulta, para ver el tipo de acceso que tenemos (Obviamente tendremos un full table scan en las tablas de este tipo de volumen):

SQL> set autotrace traceonly
SQL> select * from tabla_test where owner#=1;

2834 rows selected.
Execution Plan
———————————————————-
Plan hash value: 1026990376

——————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
——————————————————————————–
| 0 | SELECT STATEMENT | | 24608 | 30M| 174 (3)| 00:00:03 |
|* 1 | TABLE ACCESS FULL| TABLA_TEST | 24608 | 30M| 174 (3)| 00:00:03 |
——————————————————————————–

Statistics
———————————————————-
0 recursive calls
0 db block gets
2212 consistent gets
0 physical reads
0 redo size
1093152 bytes sent via SQL*Net to client
16470 bytes received via SQL*Net from client
1457 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2834 rows processed

SQL>

Ahora bien, un buen administrador de base de datos diría que para eliminar el full table scan es necesario crear un índice. Veamos los resultados luego de indexar (sin olvidar de actualizar estadística):

SQL> create index index_1_test on tabla_test(owner#);

Index created.

SQL> EXEC DBMS_STATS.gather_index_stats(‘sys’, ‘index_1_test’, estimate_percent => 100);

PL/SQL procedure successfully completed.

SQL> select * from tabla_test where owner#=1;

21834 rows selected.
Execution Plan
———————————————————-
Plan hash value: 1026990376

——————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
——————————————————————————–
| 0 | SELECT STATEMENT | | 24608 | 30M| 174 (3)| 00:00:03 |
|* 1 | TABLE ACCESS FULL| TABLA_TEST | 24608 | 30M| 174 (3)| 00:00:03 |
——————————————————————————–

Statistics
———————————————————-
0 recursive calls
0 db block gets
2319 consistent gets
0 physical reads
0 redo size
1093152 bytes sent via SQL*Net to client
16470 bytes received via SQL*Net from client
1457 SQL*Net roundtrips to/from client
3 sorts (memory)
0 sorts (disk)
2834 rows processed

SQL>

¿Que pasó? ¡Aún después de haber creado un índice y actualizar estadísticas se sigue accediendo a la tabla por full table scan!. Bueno esto puede suceder a causa de decisiones que toma el CBO, estamos leyendo una gran cantidad de datos de la tabla, el CBO piensa según los datos que él posee que es mucho mejor para la base de datos acceder a la tabla completa que utilizar un índice. ¿Pero será tan así esto?

Para asegurarnos que las consultas que hagamos utilicen realmente los índices existe un parámetro de base de datos que se llama optimizer_index_cost_adj. Con ayuda de este parámetro podemos hacer que las decisiones de acceso del optimizador hacia los datos favorezcan el uso de índices antes que del uso de FTS. Oracle recomienda una formula para asignarle un valor a este parámetro (por defecto está en 100):

optimizer_index_cost_adj = Costo FTS de la consulta/Costo con hint usando el índice*100

Ya conocemos cual es el valor del costo por FTS, 174. Ahora averiguaremos el valor del costo utilizando como ayuda el hint del índice que creamos:

SQL> select /*+ index(tabla_test index_1_test) */ * from tabla_test where owner#=1;

2834 rows selected.
Execution Plan
———————————————————-
Plan hash value: 1582054771

——————————————————————————–
————

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)
| Time |

——————————————————————————–
————

| 0 | SELECT STATEMENT | | 24608 | 30M| 499 (1)
| 00:00:06 |

| 1 | TABLE ACCESS BY INDEX ROWID| TABLA_TEST | 24608 | 30M| 499 (1)
| 00:00:06 |

|* 2 | INDEX RANGE SCAN | INDEX_1_TEST | 24608 | | 42 (3)
| 00:00:01 |

——————————————————————————–
————
Statistics
———————————————————-
0 recursive calls
0 db block gets
367 consistent gets
0 physical reads
0 redo size
2126037 bytes sent via SQL*Net to client
16470 bytes received via SQL*Net from client
1457 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2834 rows processed

Como se puede ver el costo es bastante más alto, aún así utilizando el índice. Apliquemos la fórmula y asignemos un nuevo valor a nivel de sesión para el optimizer_index_cost_adj:

costo FTS/costo indice hint * 100

174/499*100 = 34,8

Asignaremos este nuevo valor al parámetro:

SQL> alter session set optimizer_index_cost_adj = 34;

Session altered.

SQL> select * from tabla_test where owner#=1;

2834 rows selected.
Execution Plan
———————————————————-
Plan hash value: 1582054771

——————————————————————————–
————

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)
| Time |

——————————————————————————–
————

| 0 | SELECT STATEMENT | | 24608 | 30M| 100 (1)
| 00:00:02 |

| 1 | TABLE ACCESS BY INDEX ROWID| TABLA_TEST | 24608 | 30M| 100 (1)
| 00:00:02 |

|* 2 | INDEX RANGE SCAN | INDEX_1_TEST | 24608 | | 8 (0)
| 00:00:01 |

——————————————————————————–
————
Statistics
———————————————————-
13 recursive calls
0 db block gets
367 consistent gets
0 physical reads
0 redo size
2126037 bytes sent via SQL*Net to client
16470 bytes received via SQL*Net from client
1457 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
21834 rows processed

Como podemos ver luego de la modificación de este parámetro el costo y los consisten gets disminuyeron sin necesidad de recurrir a la utilización de un hint, además de eliminar el FTS.

Como Observación es bastante común por lo menos para mí observar el valor de optimizer_index_cost_adj entre 20 y 30 en las bases de datos. Es importante recalcar que el DBA siempre debe optimizar sus resultados en base a las lecturas más que por el costo. Recordemos que el Costo es un valor que Oracle representa para un plan de ejecución, es algo así como un puntaje. El verdadero afinamiento debe estar orientado a las estadisticas que te entrega el plan como por ejemplo los consistent gets.

En esta nota metalink 243269.1How does Parameter OPTIMIZER_INDEX_COST_ADJ influence Index Access” está la información original, además del comentario de otros parámetros a los cuales ponerle atención. No olvidar establecer el valor de parámetro desde el archivo SPFILE o PFILE de Oracle, sólo para efectos de prueba lo declaramos a nivel de sesión.


Originalmente escrito en: www.dbagroup.cl blog de la empresa donde presto servicios de consultor de empresas.

Oct 4, 2010

Oracle Standby: Log shipping rcp

www.felipedonoso.cl
felipe@felipedonoso.cl
RC6016
1NF3RNU5



If you need to make a Oracle Standby Database in Unix environment and you haven't the typical tools like ssh,ftp,nfs and/or Data Guard (Oracle) you can to use rcp and rsh for to transport the archived logs (and to use cksum or sum for to check the copied files).

First:

You should to have installed rsh-server, and then to configure the /etc/hosts.equiv

Second:

Execute periodically this script for to copy archived redolog files:

#!/usr/bin/ksh
# ----------------------------------------------------------------------
# Autores : Felipe Donoso Bastias
#
#
# Version : 1.1
#
# Fecha de Creacion : 14-12-2007
#
# Objetivos : Copiar los archived logs al servidor secundario
#
# Modificado : 28-12-2007
# - Se agrega comprobacion de cheksum a los archivos traspasados
# - Se modifica el formato de salida de los archivos de log
#
# Observaciones : Se comprueba la integridad de cada archivo (Checksum) a través
# del utilitario cksum.
#
# ----------------------------------------------------------------------
listado_remoto=/opt/oracle/stby/listado_remoto.txt
listado_local=/opt/oracle/stby/listado_local.txt
arch_des=
/u02/oradata/felipe
log=/opt/oracle/stby/log_shipping.log
log_hist=/opt/oracle/stby/log_shipping_hist.log
remote_host=felipe_prod
local_host=felipe_stby
rsh $remote_host ls $
arch_des/\*.arc > $listado_remoto
ls $
arch_des/*.arc > $listado_local
lista_archivos=$(sdiff -s $listado_remoto $listado_local | grep \< | awk ' { $2=R; print}') print "+----------------------------------------------------------------+" > $log
print "| Ejecucion de proceso copiado de archive |" >> $log
print "+----------------------------------------------------------------+" >> $log
print "******************************************************************" >> $log
echo "Lista de Archivos a Copiar: ">> $log
echo $lista_archivos >> $log
print "Inicio Copia de archived logs: "$(date) >> $log
for foo in $lista_archivos;do
rcp $remote_host:$foo $arch_des
cksum_local=$(cksum $foo | awk '{print $1}')
cksum_remoto=$(rsh $remote_host cksum $foo | awk '{print $1}')
#Aqui se hace una comprobacion del archivo recien copiado
keeplooping=1

while [[ $keeplooping -eq 1 ]] ; do
if [[ "$cksum_local" = "$cksum_remoto" ]] ; then
#el archived fue bien copiado
keeplooping=0
fi
if [[ "$cksum_local" != "$cksum_remoto" ]] ; then
echo "CKSUM local : $cksum_local" >> $log
echo "CKSUM remoto: $cksum_remoto" >> $log
echo "Hay que realizar la copia de nuevo de $foo" >> $log
sleep 20
rcp $remote_host:$foo $arch_des
cksum_local=$(cksum $foo | awk '{print $1}')
cksum_remoto=$(rsh $remote_host cksum $foo | awk '{print $1}')
fi
done
done
print "Fin Copia de archived logs: "$(date) >> $log
echo "Lista de Archivo no copiados: ">> $log
rsh $remote_host ls
$arch_des/\*.arc > $listado_remoto
ls
$arch_des/*.arc > $listado_local
lista_archivos=$(sdiff -s $listado_remoto $listado_local | grep \< | awk ' { $2=R; print}') echo $lista_archivos >> $log
print "+----------------------------------------------------------------+" >> $log
print "| Fin de Ejecucion de proceso |" >> $log
print "+----------------------------------------------------------------+" >> $log
print " " >> $log
print " " >> $log
print " " >> $log
print " " >> $log
cat $log >> $log_hist


Its very easy, sorry for my very BAD english.
PD: I executed this in environment ORacle 7.3 on Solaris 6
Greetings for all, in special for my Sindy friend. Felipe