Using Cacti for monitoring Microsoft SQL servers - sql

Is anyone using Cacti to monitor SQL server counters (disk queue length, i/o requests etc).
If you are, how did you go about accomplishing this? Basically I gather a number of performance counters on my SQL Servers. I need a way to create graphs and slice and dice the data that I have gathered? If you know of any other graphing solutions let me know?

Yes, done this a few times:
http://docs.cacti.net/usertemplate:host:microsoft:sqlserver
It works really well. You need access to create a login. This is the script you run which is not invasive:
/* SQL 2005/2008 */
USE [master]
GO
CREATE LOGIN [cactistats] WITH PASSWORD=SomePassword, DEFAULT_DATABASE=[master], DEFAULT_LANGUAGE=[us_english], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF
GO
EXEC sys.sp_addsrvrolemember #loginame = N'cactistats', #rolename = N'processadmin'
GO
CREATE USER [cactistats] FOR LOGIN [cactistats] WITH DEFAULT_SCHEMA=[dbo]
GO
GRANT SELECT ON [sys].[dm_os_performance_counters] TO [cactistats]
GO
/* END */
Once it's run and you've added the scripts as per the installation documentation, you will be able to graph SQL metrics.
Mike

This answer is in addition to the correctly marked answer.
if you need to monitor a particular sql server instance, then you need to edit this script file
/usr/share/cacti/site/scripts/ss_win_mssql.php
and change the line:
if (! $link = mssql_connect($host.':'.$port, $username, $password) )
to
$host = ($port == '1433' ? $host : $host.':'.$port);
if (! $link = mssql_connect($host, $username, $password) )
return;
and when creating the graphs set the hostname and instance like such:

Related

Can R access internet whilst running as an external script in SQL Server?

I run the R portion of the code in Rstudio, and it works fine.
But when I call it inside SQL Server, it runs successfully, but cant return any results, only "I've got nothin'" which is the default error of the wikifacts package when it cant find a result to return.
EXEC sp_execute_external_script
#language = N'R',
#script = N'
library(wikifacts)
query <- "Microsoft"
answer <- as.data.frame(wiki_define(query, sentence = 1))
print(answer)
'
Im just wondering if its being blocked along the way, or not possible to call external data from SQL server? And what a possible workaround could be?
Solved..!
For anyone who wants to know, I had to disable outbound firewall rules for SQL server.

Cannot restore database as file is being used by another process

I have developed this application for a store owner.I want to allow the owner to backup and restore database by using the application.the backup runs fine but the restore is causing an exception which says that - Operating system error 32( the process cannot access the file because it is being used by another process).Restore database is terminated abnormally.
using(var conn = new SqlConnection(ConnectionString))
{
using(SqlCommand cmd = conn.CreateCommand())
{
string datadirectory = Path.Combine(Environment.CurrentDirectory,#"Data");
string query = #"RESTORE DATABASE""{0}""FROM DISK= '{1}' WITH REPLACE";
string query = String.Format(query,backupfile,datadirectory + "\\Database.mdf");
conn.Open();
SqlCommand command = new SqlCommand(query,conn);
command.ExecuteNonQuery();
}
}
How can I solve this issue ? Thanks in advance.
You have to dispose of every SQLiteConnection, SQLiteCommand and SQLiteDataReader once you are done using it. The second command that you create isn't correctly being disposed off.
That aside, your code sample doesn't really make sense. You create a command that is never used. Then you create a second command that isn't properly disposed off.
Is it the restore-file that is blocking? Or is the database itself still running?
If it is the database that is being used, you can set the database in single-user-mode. Another option is taking the database temporarily offline and bring it online again. That should close all existing connections. Tip; with SSMS you can turn almost every command into an SQL script like the button to brink a database offline. Click on 'Script' and you get something like 'USE MASTER GO ALTER DATABASE [AdventureWorks] SET OFFLINE GO'.
wait, this is good news. it looks like the application is running, the db is online and live, so why do want to restore? backups are something you do daily/hourly... but restores you ONLY do if something goes wrong. of course you got an error. the db is live and sql service is using the files and it's good it didn't let you restore or else you would have lost a lot of data.
if all you want is to test the restore, then you need to shut down the sql service first.BUT, make sure you take a backup just before that so you restore the latest.

Create user script with variable domain user login

We have a DACPAC that has a create user script.
The user has a log in that needs to be set to a windows domain user
When we do a build for Test/Staging/Release we need to be able to apply a different domain and user for the users log in.
I thought we might be able to use SQLCMD variables but I just get a SQL71501 Error when trying to use this That script looks something like this:
CREATE USER [Username]
For Login [$(SQLLoginDomain)]
WITH DEFAULT_SCHEMA = [SCHEMANAME]
GO
My advice based on bitter experience is to keep anything that is environment specific out of your SQL Server Database Project. Rather, apply anything that is environment specific (permisins etc) as a separate T-SQL script after the DACPAC has been deployed. If you are doing this with Release Management I have a soup-to-nuts blog series that includes publishing DACPACs and separate permissions scripts here.The post about applying a tokenised permissions script is here.
We ended up solving this by using a post deployment script in the dacpac and as long as you do a check before trying to call the user to see if they already exist it all works as that is the only place you can use them bar the pre deployment script.
You can read the Windows domain from the sys.dm_exec_sessions system view.
For example, you could put something like this in the DACPAC's post-deployment script...
DECLARE #host_name nvarchar(128);
DECLARE #nt_domain nvarchar(128);
SELECT
#host_name = host_name,
#nt_domain = nt_domain
FROM
sys.dm_exec_sessions
WHERE
session_id = ##SPID;
-- If the domain is present, setup the login/user.
-- Otherwise, we are probably running under test environment, so we can skip this.
-- `#nt_domain = #host_name` tends to hold for LocalDB.
IF #nt_domain IS NOT NULL AND #nt_domain <> #host_name BEGIN
DECLARE #user_nonquoted nvarchar(128) = #nt_domain + '\YourUserName';
DECLARE #user nvarchar(128) = QUOTENAME(#user_nonquoted);
IF #user_nonquoted NOT IN (SELECT name FROM sys.database_principals)
EXEC ('CREATE LOGIN ' + #user + ' FROM WINDOWS');
IF #user_nonquoted NOT IN (SELECT name FROM sys.server_principals)
EXEC ('CREATE USER ' + #user + ' FOR LOGIN ' + #user);
END

Powershell to find the principal/mirror in SQL servers

I would like to know if it is possible to know if a instance of sql server is in mirror/prinicipal by running any sql query? and secondly i want to run this on say 60-80 instances everyday at 4am automatically possible? I would like to use powershell used it before quite easy to use from experience. Tks
It is possible. You will need to play around with SMO objects.
$server = "dwhtest-new"
$srv = New-Object Microsoft.SqlServer.Management.Smo.Server $server
$db = New-Object Microsoft.SqlServer.Management.Smo.Database
$dbs = $srv.Databases
foreach ($db1 in $dbs)
{
$db = New-Object Microsoft.SqlServer.Management.Smo.Database
$db = $db1
$DatabaseName = $db.Name
Write-Host $DatabaseName
Write-Host "MirroringStatus:" $db.MirroringStatus
Write-Host "DBState:" $db.Status
Write-Host
}
If your DB's mirroring is still intact you will recieve 'Synchronized' for MirroringStatus and its its the Primary it will say "Normal" for the status and if its the failover it will say "Restoring". Unfortunately there is no way, that im aware of, to just pull out the status of "Mirror" or "principle". You will jsut have to build logic to check both fo those values.
Restoring
It depends on how are you going to setup the job?
If you want to run it from one central server that collects all the information then SMO would be the way to go with PowerShell. The answer provided by KickerCost can work but would need some more work to be able to run it for multiple servers. It would be best to take his example and turn it into a working function that will allow the server names to be piped in.
If you are going to just run a job locally on each server (scheduled task or SQL Agent job) that may point to the script on a network share, then maybe output that info to a file (like servername_instance.log) you can use a one-liner with SQLPS:
dir SQLSERVER:\SQL\KRINGER\Default\Databases | Select Name, MirroringStatus
KRINGER is my server name, with a default instance. If you have named instances then replace the "default" with the instance name.
Your output from this command would be similar to this:
Name MirroringStatus
---- ---------------
AdventureWorks None
AdventureWorksDW None
Obviously I don't have any databases involved in mirroring.

Does [My]SQL have a Pre-Processor-like Facility?

I'm writing a small deployment SQL script for my first database-driven app.
In the process, I find that I repeat myself a lot, for instance:
GRANT USAGE ON *.* TO 'foo'#'localhost';
DROP USER 'foo'#'localhost';
CREATE USER 'foo'#'localhost' IDENTIFIED BY 'password';
It would be fantastic if I could use a variable or a macro to replace commonly occurring data. Is it possible to implement something like the the following snippet?
#define USER 'foo' #or "Type USER = 'foo'"
#define HOST 'localhost' #or "Type HOST = 'localhost'"
GRANT USAGE ON *.* TO USER#HOST
DROP USER USER#HOST
CREATE USER USER#HOST IDENTIFIED BY 'password'
Most SQL databases have some kind of bind variables that you can use for that.
For instance, in PostgreSQL you use the \set command in plsql:
\set user = foo
drop user :user;
create user :user identified by 'password';
However, I am not sure if MySQL have something like that. It do have variables, and since the host and user is a string, you might be able to do something like this:
select #user = 'foo';
select #host = 'localhost;
drop user #user##host;
create user #user##host identified by 'password';
If variables doesn't work with the drop and create user statements, you can always modify the mysql.user table directly, just don't forget to execute flush privileges after.
insert into user values(host,#user,PASSWORD('some_pass'),
'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
flush privileges;
You can certainly do something like:
SET #user='foo';