Physical location of FILESTREAM data - sql-server

How could I know the physical location (so I can see it in Windows Explorer) path of a FILESTREAM data that I've just inserted into DB?

There is one option for this: method PhysicalPathName(). If you are on SQL Server 2012 or upper now, this code will work for you:
SELECT stream.PhysicalPathName() AS 'Path' FROM Media
OPTION (QUERYTRACEON 5556)
For SQL Server 2008/2008 R2 you will need to enable trace flag 5556 for the whole instance:
DBCC TRACEON (5556, -1)
GO
or for the particular connection in which you are calling PhysicalPathName() method:
DBCC TRACEON (5556, -1)
GO

I know this is an older post but as it still comes up high in the Google search rankings I thought I'd post an answer. Certainly in later versions of SQL (I've not tried this on 2008) you can run the following query:
SELECT t.name AS 'table',
c.name AS 'column',
fg.name AS 'filegroup_name',
dbf.type_desc AS 'type_description',
dbf.physical_name AS 'physical_location'
FROM sys.filegroups fg
INNER JOIN sys.database_files dbf
ON fg.data_space_id = dbf.data_space_id
INNER JOIN sys.tables t
ON fg.data_space_id = t.filestream_data_space_id
INNER JOIN sys.columns c
ON t.object_id = c.object_id
AND c.is_filestream = 1
Source

As Pawel has mentioned, it is not a good idea to access the FILESTREAM files using Windows Explorer. If you are still determined to go ahead and explore this, the following tip might help.
The FILESTREAM file names are actually the log-sequence number from the database transaction log at the time the files were created. Paul Randal has explained it in this post. So One option is to find out the log sequence number and look for a file named after that in the file stream data container.

First you need to understand that the FileStream is being stored on the server hosting your SQL Server 2008 database. If you have a DBA, ask them where they created it the FileStream at. Of course, you'll then need rights to the server to navigate it to see the directories. You won't be able to manipulate the files in any way either, but you will be able to see them. Most DBA's won't be keen on letting you know where the FileStream is located at.
However, you can get at the path by a few other means. One way that comes to mind is by selecting upon the PathName() of the FileStream field. Assume that the FileStream enabled field is ReportData, and the table in which it resides is TblReports. The following t-sql syntax will yield an UNC to the location:
select top 1 ReportData.PathName(0)
from dbo.datReport
I believe you can also get at the path by other means through enterprise manager, but I forget how to at the moment.

--filestream file path
SELECT col.PathName() AS path FROM tbl

Related

How to clear SQL Server Extended Events Event File

How to clear SQL Server extended events that are stored in a file?
Background
Where are the files for SQL Server Extended Events Event File target stored?
I want to delete months worth of log files; but SQL Server doesn't tell me where the files are:
I would follow the advice on Microsoft's SQL Server forums:
Clear events in file target?
Simply stop the session and delete .xel file if it’s no longer required.
Attempt#3
I tried doing the single most obvious thing that any user interface designer worth their salt would have created from the beginning: Right-click the event file target, and select:
Clear
Delete
Purge
Empty
Except there is no option to do any of those obvious things:
Attempt#4
I also tried going into the Extended Events menu, and clicking Clear Data. But the option is inexplicably disabled:
Attempt#5
I also tried to script the Extended Events Session, in order to see where it is storing the files. But of course SQL Server team is not helpful:
ADD TARGET package0.event_file(SET filename=N'Expensive Queries',max_file_size=(25),max_rollover_files=(4)),
Attempt#6
In SQL Server Profiler. If you wanted to clear the events you pushed the button to clear the events:
SQL Profiler is deprecated, and it's replacement provides no way to clear the events.
What is the way to clear the events?
Bonus Reading
Query to clear sql server logs over a certain age
Clear events in file target?
BOL: Targets for Extended Events in SQL Server
BOL: Event File Target
By default the path seems like it would be
C:\Program Files\Microsoft SQL Server\MSSQLXX.MSSQLSERVER\MSSQL\Log\*.xel
or basically wherever the system files are kept for SQL Server (i.e. the default ERRORLOG location). If there is nothing there then it may be that your Extended Event is set to ring buffer in which case only the latest information is kept and it's stored in memory. Seems the only way to clear the log in this case would be to stop and start the session.
You can also use
DECLARE #SQLDataRoot VARCHAR(400)
EXEC master..xp_instance_regread #rootkey = 'HKEY_LOCAL_MACHINE',
#key = 'SOFTWARE\Microsoft\MSSQLServer\Setup',
#value_name = 'SQLDataRoot', #value = #SQLDataRoot OUTPUT
SELECT #SQLDataRoot
Here's how you get the file path:
SELECT n.value('(#name)[1]','varchar(255)') AS FilePath
FROM
(
SELECT CAST(t.target_data AS XML) target_data
FROM sys.dm_xe_sessions s
INNER JOIN sys.dm_xe_session_targets t ON t.event_session_address = s.address
WHERE s.name = 'Your Session Name'
AND t.target_name = N'event_file'
) AS tab
CROSS APPLY [target_data].[nodes]('EventFileTarget/File') AS [q] ([n]);
The only way I've found to clear the data is to drop the session delete the files and then create the session again.
As is mentioned above, event file is in C:\Program Files\Microsoft SQL Server\MSSQLXX.MSSQLSERVER\MSSQL\Log\ - so you can delete it from disk (in case you have access and permission to do it). In case you have no acces/permission to SQL server or file (from any reason), you can do it from SQL Management studio.
In this case, you can remove current file and add (create) new file again. It can be done with or without stopping event. Path : Properties -> Data Storage
Open "Properties":
Go to "Data Storage" and remove file
Add new file:
Detect event file file path with a query like this
SELECT CAST(t.target_data AS XML).value('(EventFileTarget/File/#name)[1]', 'VARCHAR(MAX)') FilePathAndName
FROM sys.dm_xe_sessions s WITH (NOLOCK)
JOIN sys.dm_xe_session_targets t WITH (NOLOCK) ON s.address = t.event_session_address
WHERE t.target_name = 'event_file'
AND s.name = 'tempdbgrowth' -- <-- replace tempdbgrowth with extended event name
Delete the file (or files) from file system
SSMS right-click on extended-event (higher level then event file) and select "Refresh"

SQL Server 2012 - Finding out which transaction logs have been applied to a NORECOVER db

I have a copy of an offsite production database used for reporting which is running on SQL Server 2012. I want to start updating it hourly with transaction logs from that offsite production database.
No big deal, restore a full backup (w/ NORECOVERY) to get things started and apply the transaction logs (w/ NORECOVERY) as they come in.
However, in the event of a problem with the restore (or with getting the log files) I could end up with several transaction log files, some of which have been applied and others that have not. When that happens, how do I figure out which file to start with in my TSQL script?
I tried looking in the restore history table like this:
select distinct
h.destination_database_name,
h.restore_date,
s.server_name,
m.physical_device_name as backup_device,
f.physical_name
from
msdb..restorehistory h
inner join
msdb..backupfile f on h.backup_set_id = f.backup_set_id
inner join
msdb..backupset s on f.backup_set_id = s.backup_set_id
inner join
msdb..backupmediafamily m on s.media_set_id = m.media_set_id
where
h.destination_database_name = 'mydb'
and h.restore_date > (GETDATE() -0.5)
order by
h.restore_date
But checking restorehistory is no good because the NORECOVERY flag means no records have been added in that table. So is there another way to check this, via T-SQL, that works for a NORECOVERY database?
Assuming this is a rare manual operation, the simplest way to is scan the errorlog.
SQL Server's built-in log shipping (and some third party implementations) have tables, views and user interfaces that make this simpler.

Local SQL Server: The specified procedure could not be found

This problem has appeared on my PC a few days ago, without any changes I have made to the Visual Studio/SQL Server settings.
When trying to perform any manual operation on the database file (*.mdf) in Visual Studio, I get the following error:
The specified procedure could not be found. (Exception from HRESULT: 0x8007007F)
(For example, when trying to create a new table, or when showing an existing table's data)
How I can fix this error?
Be sure you or someone else has not changed your rights on master. In order to add anything a record is added to that table.
Addendum:
You can run the following script to determine who has what permissions and whether they are implicit or explicit.
WITH perms_cte as
(
select USER_NAME(p.grantee_principal_id) AS principal_name,
dp.principal_id,
dp.type_desc AS principal_type_desc,
p.class_desc,
OBJECT_NAME(p.major_id) AS object_name,
p.permission_name,
p.state_desc AS permission_state_desc
from sys.database_permissions p
inner JOIN sys.database_principals dp
on p.grantee_principal_id = dp.principal_id
)
--users
SELECT p.principal_name, p.principal_type_desc, p.class_desc, p.[object_name], p.permission_name, p.permission_state_desc, cast(NULL as sysname) as role_name
FROM perms_cte p
WHERE principal_type_desc <> 'DATABASE_ROLE'
UNION
--role members
SELECT rm.member_principal_name, rm.principal_type_desc, p.class_desc, p.object_name, p.permission_name, p.permission_state_desc,rm.role_name
FROM perms_cte p
right outer JOIN (
select role_principal_id, dp.type_desc as principal_type_desc, member_principal_id,user_name(member_principal_id) as member_principal_name,user_name(role_principal_id) as role_name--,*
from sys.database_role_members rm
INNER JOIN sys.database_principals dp
ON rm.member_principal_id = dp.principal_id
) rm
ON rm.role_principal_id = p.principal_id
order by 1
--- thanks to Jamie Thomson for this ditty
A more few suggestions;
Trace the call using profiler and confirm you are connecting as the user you think you are - sp_who2 might be another way to verify that.
Verify your process is in the correct database. Use the c# connection and run SELECT DB_NAME() - write the result somewhere you can read to confirm.
If this works from one environment but not another I would strongly suspect the connection string.
Check that you do not have authentication errors reported in your SQL logs. These again would indicate possible connection issues.
The conventional wisdom on this error is that it likely reflects a lost or corrupted DLL (in either SQL Server or Visual Studio). And the SOP is to reinstall, though it seems that that does not always work either.
Try to run Visual Studio as administrator
Right click Visual Studio --> Run as Administrator.
Try to connect to the database in SQL Server Management Studio. That'll at least narrow down whether it's a database permission issue or something else. Also, check to confirm that the database exists and you have permission to access it. (Like Joe suggested.)
Assuming that checks out... My googling found a guy with a very similar sounding problem. He said that the runas administrator thing Adel suggested worked for him, but there were other issues that could also cause the error message, including VS not being able to find the IIS virtual server specified in the Web Application Project file (permissions? renamed?). Confirm that the file exists and you have permission to access it.
http://connect.microsoft.com/VisualStudio/feedback/details/317124/system-runtime-interopservices-comexception-in-webapplication-project

Find unused stored procedures in code?

Is there an easier way of cleaning up a database that has a ton of stored procedures that I'm sure there are some that aren't used anymore other than one by one search.
I'd like to search my visual studio solution for stored procedures and see which ones from the database aren't used any longer.
You could create a list of the stored procedures in the database. Store them into a file.
SELECT *
FROM sys.procedures;
Then read that file into memory and run a large regex search across the source files for each entry. Once you hit the first match for a given stored procedure, you can move on.
If there are no matches for a given stored procedure, you probably can look more closely at that stored procedure and may even be able to remove it.
I'd be careful removing stored procedures - you also need to check that no other stored procedures depend on your candidate for removal!
I would use the profiler and set up a trace. The big problem is tracking SPs which are only used monthly or annually.
Anything not showing up in the trace can be investigated. I sometimes instrument individual SPs to log their invocations to a table and then review the table for activity. I've even had individual SPs instrumented to send me email when they are called.
It is relatively easy to ensure that an SP is not called from anywhere else in the server by searching the INFORAMTION_SCHEMA.ROUTINES or in source code with GREP. It's a little harder to check in SSIS packages and jobs.
But none of this eliminates the possibility that there might be the occasional SP which someone calls manually each month from SSMS to correct a data anomaly or something.
Hmmm... you could search your solution for code which calls a stored proc, like this (from the DAAB)
using (DbCommand cmd = DB.GetStoredProcCommand("sp_blog_posts_get_by_title"))
{
DB.AddInParameter(cmd, "#title", DbType.String,title);
using (IDataReader rdr = DB.ExecuteReader(cmd))
result.Load(rdr);
}
Search for the relevant part of the first line:
DB.GetStoredProcCommand("
Copy the search results from the "find results" pane, and compare to your stored proc list in the database (which you can generate with a select from the sysObjects table if you're using SQL Server).
If you really want to get fancy, you could write a small app (or use GREP or similar) to perform a regex match against your .cs files to extract a list of stored procedures, sort the list, generate a list of stored procs from your database via select from sysobjects, and do a diff. That might be easier to automate.
UPDATE Alternatively, see this link. The author suggest setting up a trace for a period of a week or so and comparing your list of procs against those found in the trace. Another author suggested: (copied)
-- Unused tables & indexes. Tables have index_id’s of either 0 = Heap table or 1 = Clustered Index
SELECT OBJECTNAME = OBJECT_NAME(I.OBJECT_ID), INDEXNAME = I.NAME, I.INDEX_ID
FROM SYS.INDEXES AS I
INNER JOIN SYS.OBJECTS AS O
ON I.OBJECT_ID = O.OBJECT_ID
WHERE OBJECTPROPERTY(O.OBJECT_ID,'IsUserTable') = 1
AND I.INDEX_ID
NOT IN (SELECT S.INDEX_ID
FROM SYS.DM_DB_INDEX_USAGE_STATS AS S
WHERE S.OBJECT_ID = I.OBJECT_ID
AND I.INDEX_ID = S.INDEX_ID
AND DATABASE_ID = DB_ID(db_name()))
ORDER BY OBJECTNAME, I.INDEX_ID, INDEXNAME ASC
which should find objects that haven't been used since a specified date. Note that I haven't tried either of these approaches, but they seem reasonable.

How can I get a list of all of the user databases via t-sql?

I want to get a list of all of the user databases from an mssql server instance. What's the best way to do this?
I know I can select from sys.databases, but I don't see any way to filter out system databases besides hardcoding a list of names to exclude.
I need the script to work on 2000/2005 and 2008.
If the approach I listed above is the only way to go, what are list of names I should exclude? I don't know if 2005 or 2008 added any new system databases off the top of my head.
Was looking in to this again today and decided to profile what Management Studio was doing to populate the Object Explorer details.
Turns out the solution Microsoft have implemented is pretty simplistic and boils down to the following:
SELECT *
FROM master.sys.databases
WHERE Cast(CASE WHEN name IN ('master', 'model', 'msdb', 'tempdb') THEN 1 ELSE is_distributor END As bit) = 0
Please note that this was performed using SSMS 2008R2 (10.50.4033.0).
The first query will return a table with data regarding all of the databases on the instance:
Select *
From sys.databases
From this table you'll notice you can narrow down the scope of data you're looking for by using the WHERE clause. For example, the following queries will essentially return the same result table (the one you're most likely looking for):
Select *
From sys.databases
Where database_id > 5
Select *
From sys.databases
Where len(owner_sid)>1
These queries will work in SQL Server 2008 and 2012.
On SQL Server 2008 R2 Express, looks like I cannot reliably use any of the above methods. INFORMATION_SCHEMA.SCHEMATA only shows me information in the current database, db_id (database_id) #5 is my first user database, and owner_sid on two of my user databases on one of my mirrored databases (running on SQL Server 2008 R2 Standard) shows owner_sid = 1 for my two most recently created databases. (PablolnNZ's comment above is correct: I did not set an explicit owner for those two databases so it still shows as having an owner of 'sa'.)
The only reliable means I was able to use was the following:
SELECT name FROM sys.databases
WHERE name NOT IN ('master', 'model', 'tempdb', 'msdb', 'Resource')
This works in 2005, not 100% sure about the other versions but I think it will fly. It's a bit of a hack but might get you what you need:
select * from sys.databases where len(owner_sid)>1
As nasty as it sounds to hardcode things. The names and number of system databases has been fairly consistent for several versions of SQL. However, if that is too unpleasant you could semi-hardcode them into a table and then plug that into your query.
Not sure if you can offhand. One note -- on 2k you'll have to use master.dbo.sysdatabases and not master.sys.databases (which doesn't exist in 2k).
Starting with SQL Server 2008 you have access to a view called sys.databases which when joined with sys.server_principals can eliminate the databases owned by sa, which you can (most often) safely discern are the "system databases". Thus, allowing you to filter these items out.
select
d.name
,d.database_id
from
sys.databases d
join
sys.server_principals p
on p.sid = d.owner_sid
where
p.name <> 'sa';

Resources