SQL Profiler shows high duration on unknown TextData - sql-server

I have been profiling my web app's connection to the sql server for the last 24 hours.
Out of 1.226.709 batchcompleted I have 36 with the duration over 0.1 second.
Out of the 36 I have 4 unknown statements. And here I hoped some of you could help me tell what these are about and from where they come?! :)
The first concerns me a bit, cause it have a duration over 1 second.
(The trace were saved to a table in the database, which is why all the durations are in microseconds)
TextData: SELECT 'Server[#Name=' + quotename(CAST( serverproperty(N'Servername') AS sysname),'''') + ']' + '/Collation[#Name=' + quotename(cl.name,'''') + ']' AS [Urn], cl.name AS [Name], CAST(COLLATIONPROPERTY(name, 'CodePage') AS int) AS [CodePage], CAST(COLLATIONPROPERTY(name, 'LCID') AS int) AS [LocaleID], CAST(COLLATIONPROPERTY(name, 'ComparisonStyle') AS int) AS [ComparisonStyle], cl.description AS [Description], CAST(COLLATIONPROPERTY(name, 'Version') AS int) AS [CollationVersion] FROM sys.fn_helpcollations() cl ORDER BY [Name] ASC
CPU: 93
Reads: 0
Writes: 0
Duration: 1013301
ApplicationName Microsoft SQL Server Management Studio - Transact-SQL IntelliSense
TextData: select IndA.name, IndA.index_id, IndA.fill_factor, IndA.is_padded, IndA.is_disabled,IndA.is_hypothetical, IndA.allow_row_locks, IndA.allow_page_locks,IndA.spatial_index_type, IndB.bounding_box_xmin, IndB.bounding_box_ymin, IndB.bounding_box_xmax, IndB.bounding_box_ymax, IndB.level_1_grid, IndB.level_2_grid, IndB.level_3_grid, IndB.level_4_grid, IndB.cells_per_object, ind_col.index_column_id, col.name as column_nName, ind_col.key_ordinal, ind_col.is_descending_key, ind_col.column_id, st.no_recompute from (sys.spatial_indexes IndA left outer join sys.spatial_index_tessellations IndB on IndB.object_id = IndA.object_id and IndB.index_id = IndA.index_id) inner join(sys.internal_tables IntT inner join sys.stats st on st.object_id = IntT.object_id and st.stats_id = 1) on IntT.parent_id = IndA.object_id and IntT.parent_minor_id = IndA.index_id inner join sys.index_columns ind_col on ind_col.object_id = IndA.object_id and ind_col.index_id = IndA.index_id inner join sys.columns col on col.object_id = ind_col.object_id and col.column_id = ind_col.column_id where IndA.object_id = object_id(N'dbo.rapports') order by IndA.index_id, ind_col.key_ordinal
CPU: 109
Reads: 216
Writes: 0
Duration: 148322
ApplicationName Microsoft SQL Server Management Studio
TextData: select col.name, col.column_id, st.name as DT_name, schema_name(st.schema_id) as DT_schema, col.max_length, col.precision, col.scale, bt.name as BT_name, col.collation_name, col.is_nullable, col.is_ansi_padded, col.is_rowguidcol, col.is_identity, case when(idc.column_id is null) then null else CONVERT(nvarchar(40), idc.seed_value) end, case when(idc.column_id is null) then null else CONVERT(nvarchar(40), idc.increment_value) end, CONVERT(bit, case when(cmc.column_id is null) then 0 else 1 end) as is_computed, convert(bit, ColumnProperty(col.object_id, col.name, N'IsIdNotForRepl')) as IsIdNotForRepl, col.is_replicated, col.is_non_sql_subscribed, col.is_merge_published, col.is_dts_replicated, col.rule_object_id, robj.name as Rul_name, schema_name(robj.schema_id) as Rul_schema, col.default_object_id, OBJECTPROPERTY(col.default_object_id, N'IsDefaultCnst') as is_defcnst, dobj.name as def_name, schema_name(dobj.schema_id) as def_schema, CONVERT(bit, case when (ftc.column_id is null) then 0 else 1 end) as is_FullTextCol, col_name(col.object_id, ftc.type_column_id) FT_type_column, ftc.language_id as FT_language_id, case when(cmc.column_id is null) then null else cmc.definition end as formular, case when(cmc.column_id is null) then null else cmc.is_persisted end as is_persisted, defCst.definition, COLUMNPROPERTY(col.object_id, col.name, 'IsDeterministic') as IsDeterministic, xmlcoll.name as xmlSchema_name, schema_name(xmlcoll.schema_id) as xmlSchema_schema, col.is_xml_document, col.is_sparse, col.is_column_set from sys.columns col left outer join sys.types st on st.user_type_id = col.user_type_id left outer join sys.types bt on bt.user_type_id = col.system_type_id left outer join sys.objects robj on robj.object_id = col.rule_object_id and robj.type = 'R' left outer join sys.objects dobj on dobj.object_id = col.default_object_id and dobj.type = 'D' left outer join sys.default_constraints defCst on defCst.parent_object_id = col.object_id and defCst.parent_column_id = col.column_id left outer join sys.identity_columns idc on idc.object_id = col.object_id and idc.column_id = col.column_id left outer join sys.computed_columns cmc on cmc.object_id = col.object_id and cmc.column_id = col.column_id left outer join sys.fulltext_index_columns ftc on ftc.object_id = col.object_id and ftc.column_id = col.column_id left outer join sys.xml_schema_collections xmlcoll on xmlcoll.xml_Collection_id = col.xml_Collection_id where col.object_id = object_id(N'dbo.rapports') order by col.column_id
CPU: 215
Reads: 6895
Writes: 0
Duration: 142054
ApplicationName Microsoft SQL Server Management Studio
TextData: SELECT dtb.name AS [Name], dtb.database_id AS [ID], CAST(case when dtb.name in ('master','model','msdb','tempdb') then 1 else dtb.is_distributor end AS bit) AS [IsSystemObject], CAST(has_dbaccess(dtb.name) AS bit) AS [IsAccessible], dtb.collation_name AS [Collation], dtb.name AS [DatabaseName2] FROM master.sys.databases AS dtb ORDER BY [Name] ASC
CPU: 15
Reads: 324
Writes: 0
Duration: 111258
ApplicationName Microsoft SQL Server Management Studio - Transact-SQL IntelliSense
Extra info!
I run a script every night to backup the database. I have no idea if the 4 statements have nothing to do with that. The statement for the backup is the following:
TextData: declare #DBName varchar(200) declare #Filename varchar(1000) declare #Description varchar(1000) DECLARE AllDatabases CURSOR FOR SELECT name AS Name FROM MASTER.DBO.SYSDATABASES WHERE [NAME] NOT IN('MODEL', 'tempdb') OPEN AllDatabases FETCH NEXT FROM AllDatabases INTO #DBName WHILE ##FETCH_STATUS = 0 BEGIN print '' print '' print 'Backing up database ' + #DBName -- Backup the database set #Filename = 'D:\backup\' + convert(varchar, getDate(), 112) + ' - ' + #DBName + '.bak' set #Description = 'Full backup of database ' + #Filename BACKUP DATABASE #DBName TO DISK = #Filename WITH INIT , NOUNLOAD , NAME = #Description, NOSKIP , STATS = 10, NOFORMAT FETCH NEXT FROM AllDatabases INTO #DBName END CLOSE AllDatabases DEALLOCATE AllDatabases
CPU: 219
Reads: 2569
Writes: 83
Duration: 4478260
Oh yeah and... I'm not used to profiling my SQL Server. Are there any tips you can give? :) I have of course been googling the topic.

After adding the ApplicationName column you can see that the queries are being run by SSMS to gather metadata about the database. SSMS needs all sorts of metadata to display databases, objects, logins and so on (you can see the reference to Intellisense too), so it's completely normal to see it querying the server. Unless you have a performance problem of some kind that you can directly link to these queries from SSMS, I would forget about them.

This same query is also responsible for hangs of SMSS when changig from one server to another in object explorer. Just kill the process running this query and on goes the show.

Related

SQL query optimization using dynamic query

I have the following stored procedure. It uses a common table expression and a table valued function. It takes 600 ms to execute this sp. I used dynamic query to avoid the use of a table valued function and the the execution time reduced to around 300 ms. Is it possible to further tune this select query so that the execution time comes down to around 100 ms.
--EXEC Sp_GetTripListByBusinesses 1,2,3,4,5,6,7,8,9,10,11,12,13,14,93', 1, 3, 1
CREATE PROCEDURE [dbo].[Sp_GetTripListByBusinesses]
(
#BusinessID varchar (max),
#TripFlag int,
#TripFrom INT,
#IsAllTrip INT
)
AS
BEGIN
DECLARE #Query nvarchar(max) = '';
SET #Query= '
;With CTE
AS
(
select TripID, count(TripNotesID) as NoteCount from tripnotes WHERE
TripNoteTypeID != 13 group by TripID
)
SELECT TRP.[TripID]
,isnull(TRP.[AssignedTruckerID],0) as AssignedTruckerID
,TRP.[BusinessID] AS BusinessID
,isnull(TRP.[TruckRate],''0.0'') as TruckRate
,TRP.[RequestedDatetime]
,TRP.[ArrivedDatetime]
,TRP.[DepartedDatetime]
,TRP.[TripStatusID]
,isnull(TRP.[IsDelayed] ,0) as IsDelayed
,isnull(TRP.[IsStopped] ,0) as IsStopped
,isnull(TRP.[RepeatUntilStop],'''') AS RepeatUntilStop
,TRP.[ArrivedAtBusinessDatetime]
,TRP.[OrgSiteID]
,TRP.[OriginCustomerID] AS OrgCustomerID
,OS.[SiteName] + '' / '' + ISNULL(OS.[AS400_ID],'''') AS OrgSiteName
,isnull(OS.[SiteLat],''0.0'') as OrgSiteLat
,isnull(OS.[SiteLong],''0.0'') as OrgSiteLong
,isnull(OS.[WaypointsAvl],0) as OrgWaypointsAvl
,isnull(OS.[NearestRoadwayLat],''0.0'') as OrgNearestRoadwayLat
,isnull(OS.[NearestRoadwayLong],''0.0'') as OrgNearestRoadwayLong
,OS.[SiteStatus] AS OrgSiteStatus
,OS.[AS400_ID] AS OrgAS400_ID
,TRP.[DestSiteID]
,TRP.[DestCustomerID] AS DestCustomerID
,DS.[SiteName] + '' / '' + ISNULL(DS.[AS400_ID],'''') AS DestSiteName
,isnull(DS.[SiteLat],''0.0'') as DestSiteLat
,isnull(DS.[SiteLong],''0.0'') as DestSiteLong
,isnull(TRK.FirstName,'''') + '' '' + ISNULL(TRK.[LastName],'''') AS
TruckerName
,isnull(TRK.[TruckType],''A'') as TruckType
,TRK.[Mobile] AS TruckerMobile
,B.[Name] AS BusinessName
,isnull(B.BusinessLat,''0.0'') as BusinessLat
,isnull(B.BusinessLong,''0.0'') as BusinessLong
,B.ContactNo AS BusinessContactNo
,B.Address1 AS BusinessAddress1
,B.Address2 AS BusinessAddress2
,B.City AS BusinessCity
,B.[State] AS BusinessState
,B.Zip AS BusinessZip
,TS.[StatusText]
,CASE WHEN TA.[BillOfLading] IS NULL THEN ''NA'' ELSE ''BOL'' END AS
BillOfLading
,CASE WHEN TA.[ScaleTicket] IS NULL THEN ''NA'' ELSE ''ST'' END AS
ScaleTicket
,CASE WHEN TA.[OriginScaleTicket] IS NULL THEN ''NA'' ELSE ''OST'' END AS
OriginScaleTicket
,TRP.OriginGrossBushels
,TRP.DestGrossBushels
,(SELECT count(TripNotesID) FROM dbo.[TripNotes]) as Notes
,TRP.MainTripID
,Convert(DATE, TRP.[RequestedDatetime]) AS TripDate
,1 as TripOrderNo
,isnull(TRP.IsSiteDelayed ,0) as IsSiteDelayed
,TRP.CommodityID
,C.CommodityName
,CTE.NoteCount
,TRP.InvoiceId
,TRP.OneWayMiles as OneWayMile
,OS.SiteType AS OriginSiteType
,DS.SiteType AS DestSiteType
FROM dbo.[Trip] AS TRP
INNER JOIN dbo.[Site] AS OS ON TRP.OrgSiteID = OS.SiteID
INNER JOIN dbo.[Site] AS DS ON TRP.DestSiteID = DS.SiteID
LEFT JOIN dbo.[Trucker] AS TRK ON TRP.AssignedTruckerID = TRK.TruckerID AND ISNULL(TRK.TruckerStatus,''A'') = ''A''
LEFT JOIN dbo.[Commodity] as C ON TRP.CommodityID = C.CommodityID AND C.RecordStatus = ''A''
INNER JOIN dbo.[Business] AS B ON B.BusinessID = TRP.BusinessID
LEFT JOIN dbo.[TripStatus] AS TS ON TS.TripStatusID = TRP.TripStatusID
LEFT JOIN dbo.[TripAsset] AS TA ON TA.TripID = TRP.TripID
LEFT JOIN CTE ON CTE.TripID = TRP.TripID
WHERE
TRP.RecordStatus=''A'' and
TRP.BusinessID in (' +#BusinessID + ')
ORDER BY TRP.RequestedDatetime ASC';
execute sp_executesql #Query;
END

Microsoft SQL Server 2016 - SSMS, cannot expand tables for a database

There are many databases on my server, recently of them one (which I am the dbo on) has become inaccessible through SSMS. When I expand the tables node in 'object explorer' for this database I get the following error:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression. (.Net SqlClient Data Provider)
However, I can execute selects successfully on that database and other users are not having this problem.
I have;
Checked my login for incorrect settings.
Checked my user for incorrect settings.
Restarted the SQL Server Engine.
Repaired SSMS using the installer utility.
Would very much appreciate your input, I am stumped (this has never happened before).
EDIT: After tracing using SQL Profiler and causing this event I extracted the query and ran it in a SSMS session window. The returned results are from the wrong database.
EDIT: Further to this, I ran dbcc checkdb(databasename) and no errors were returned, I then did the same for master, no errors were returned.
EDIT: The query being executed when I expand the table folder:
exec sp_executesql N'SELECT
tbl.name AS [Name],
SCHEMA_NAME(tbl.schema_id) AS [Schema],
''Server[#Name='' + quotename(CAST(
serverproperty(N''Servername'')
AS sysname),'''''''') + '']'' + ''/Database[#Name='' + quotename(db_name(),'''''''') + '']'' + ''/Table[#Name='' + quotename(tbl.name,'''''''') + '' and #Schema='' + quotename(SCHEMA_NAME(tbl.schema_id),'''''''') + '']'' AS [Urn],
tbl.create_date AS [CreateDate],
CAST(tbl.is_memory_optimized AS bit) AS [IsMemoryOptimized],
CAST(CASE idx.type WHEN 5 THEN 1 ELSE 0 END AS bit) AS [HasClusteredColumnStoreIndex],
CAST(tbl.is_remote_data_archive_enabled AS bit) AS [RemoteDataArchiveEnabled],
tbl.temporal_type AS [TemporalType],
CAST(CASE WHEN ''PS''=dsidx.type THEN 1 ELSE 0 END AS bit) AS [IsPartitioned],
CAST(
ISNULL((SELECT 1 from sys.all_columns
WHERE object_id = tbl.object_id
AND is_sparse = 1), 0)
AS bit) AS [HasSparseColumn]
FROM
sys.tables AS tbl
LEFT OUTER JOIN sys.periods as periods ON periods.object_id = tbl.object_id
LEFT OUTER JOIN sys.tables as historyTable ON historyTable.object_id = tbl.history_table_id
INNER JOIN sys.indexes AS idx ON
idx.object_id = tbl.object_id and (idx.index_id < #_msparam_0 or (tbl.is_memory_optimized = 1 and idx.index_id = (select min(index_id) from sys.indexes where object_id = tbl.object_id)))
LEFT OUTER JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = idx.data_space_id
WHERE
(CAST(
case
when tbl.is_ms_shipped = 1 then 1
when (
select
major_id
from
sys.extended_properties
where
major_id = tbl.object_id and
minor_id = 0 and
class = 1 and
name = N''microsoft_database_tools_support'')
is not null then 1
else 0
end
AS bit)=#_msparam_1 and tbl.is_filetable=#_msparam_2 and CAST(tbl.is_memory_optimized AS bit)=#_msparam_3 and tbl.temporal_type=#_msparam_4 and CAST(tbl.is_external AS bit)=#_msparam_5)
ORDER BY
[Schema] ASC,[Name] ASC',N'#_msparam_0 nvarchar(4000),#_msparam_1 nvarchar(4000),#_msparam_2 nvarchar(4000),#_msparam_3 nvarchar(4000),#_msparam_4 nvarchar(4000),#_msparam_5 nvarchar(4000)',#_msparam_0=N'2',#_msparam_1=N'0',#_msparam_2=N'0',#_msparam_3=N'0',#_msparam_4=N'0',#_msparam_5=N'0'
EDIT: As a work-around, I reinstalled the SSMS 2014. I can access my tables through here.
There is nothing wrong with your database, it's a known issue with SSMS 16.5.2 and has been reported to product team. Please revert back to previous release of SSMS if it causes too much trouble. For more information, please refer to this thread.
Apparently this only happens when the database have table(s) with more than one sparse column.
Try it's
SELECT
NAME
FROM [base].SYS.triggerS
WHERE parent_class_desc = 'DATABASE'
Take the trigger name and perform the procedure below
DISABLE TRIGGER [dbo].[trigger_name]

Forcing SQL Server to pre-cache entire database into memory

We have a client site with a 50Gb SQL 2012 database on a server with 100+ Gb of RAM.
As the application is used, SQL server does a great job of caching the db into memory but the performance increase from the caching occurs the SECOND time a query is run, not the first.
To try to maximize cache hits the first time queries are run, we wrote a proc that iterates through every index of every table within the entire DB, running this:
SELECT * INTO #Cache
FROM ' + #tablename + ' WITH (INDEX (' + #indexname + '))'
In an attempt to force a big, ugly, contrived read for as much data as possible.
We have it scheduled to run every 15 minutes, and it does a great job in general.
Without debating other bottlenecks, hardware specs, query plans, or query optimization, does anybody have any better ideas about how to accomplish this same task?
UPDATE
Thanks for the suggestions. Removed the "INTO #Cache". Tested & it didn't make a difference on filling the buffer.
Added: Instead of Select *, I'm selecting ONLY the keys from the Index. This (obviously) is more to-the-point and is much faster.
Added: Read & Cache Constraint Indexes also.
Here's the current code: (hope it's useful for somebody else)
CREATE VIEW _IndexView
as
-- Easy way to access sysobject and sysindex data
SELECT
so.name as tablename,
si.name as indexname,
CASE si.indid WHEN 1 THEN 1 ELSE 0 END as isClustered,
CASE WHEN (si.status & 2)<>0 then 1 else 0 end as isUnique,
dbo._GetIndexKeys(so.name, si.indid) as Keys,
CONVERT(bit,CASE WHEN EXISTS (SELECT * FROM sysconstraints sc WHERE object_name(sc.constid) = si.name) THEN 1 ELSE 0 END) as IsConstraintIndex
FROM sysobjects so
INNER JOIN sysindexes si ON so.id = si.id
WHERE (so.xtype = 'U')--User Table
AND ((si.status & 64) = 0) --Not statistics index
AND ( (si.indid = 0) AND (so.name <> si.name) --not a default clustered index
OR
(si.indid > 0)
)
AND si.indid <> 255 --is not a system index placeholder
UNION
SELECT
so.name as tablename,
si.name as indexname,
CASE si.indid WHEN 1 THEN 1 ELSE 0 END as isClustered,
CASE WHEN (si.status & 2)<>0 then 1 else 0 end as isUnique,
dbo._GetIndexKeys(so.name, si.indid) as Keys,
CONVERT(bit,0) as IsConstraintIndex
FROM sysobjects so
INNER JOIN sysindexes si ON so.id = si.id
WHERE (so.xtype = 'V')--View
AND ((si.status & 64) = 0) --Not statistics index
GO
CREATE PROCEDURE _CacheTableToSQLMemory
#tablename varchar(100)
AS
BEGIN
DECLARE #indexname varchar(100)
DECLARE #xtype varchar(10)
DECLARE #SQL varchar(MAX)
DECLARE #keys varchar(1000)
DECLARE #cur CURSOR
SET #cur = CURSOR FOR
SELECT v.IndexName, so.xtype, v.keys
FROM _IndexView v
INNER JOIN sysobjects so ON so.name = v.tablename
WHERE tablename = #tablename
PRINT 'Caching Table ' + #Tablename
OPEN #cur
FETCH NEXT FROM #cur INTO #indexname, #xtype, #keys
WHILE (##FETCH_STATUS = 0)
BEGIN
PRINT ' Index ' + #indexname
--BEGIN TRAN
IF #xtype = 'V'
SET #SQL = 'SELECT ' + #keys + ' FROM ' + #tablename + ' WITH (noexpand, INDEX (' + #indexname + '))' --
ELSE
SET #SQL = 'SELECT ' + #keys + ' FROM ' + #tablename + ' WITH (INDEX (' + #indexname + '))' --
EXEC(#SQL)
--ROLLBACK TRAN
FETCH NEXT FROM #cur INTO #indexname, #xtype, #keys
END
CLOSE #cur
DEALLOCATE #cur
END
GO
First of all, there is a setting called "Minumum Server Memory" that looks tempting. Ignore it. From MSDN:
The amount of memory acquired by the Database Engine is entirely dependent on the workload placed on the instance. A SQL Server instance that is not processing many requests may never reach min server memory.
This tells us that setting a larger minimum memory won't force or encourage any pre-caching. You may have other reasons to set this, but pre-filling the buffer pool isn't one of them.
So what can you do to pre-load data? It's easy. Just set up an agent job to do a select * from every table. You can schedule it to "Start automatically when Sql Agent Starts". In other words, what you're already doing is pretty close to the standard way to handle this.
However, I do need to suggest three changes:
Don't try to use a temporary table. Just select from the table. You don't need to do anything with the results to get Sql Server to load your buffer pool: all you need to do is the select. A temporary table could force sql server to copy the data from the buffer pool after loading... you'd end up (briefly) storing things twice.
Don't run this every 15 minutes. Just run it once at startup, and then leave it alone. Once allocated, it takes a lot to get Sql Server to release memory. It's just not needed to re-run this over and over.
Don't try to hint an index. Hints are just that: hints. Sql Server is free to ignore those hints, and it will do so for queries that have no clear use for the index. The best way to make sure the index is pre-loaded is to construct a query that obviously uses that index. One specific suggestion here is to order the results in the same order as the index. This will often help Sql Server use that index, because then it can "walk the index" to produce the results.
This is not an answer, but to supplement Joel Coehoorn's answer, you can look at the table data in the cache using this statement. Use this to determine whether all the pages are staying in the cache as you'd expect:
USE DBMaint
GO
SELECT COUNT(1) AS cached_pages_count, SUM(s.used_page_count)/COUNT(1) AS total_page_count,
name AS BaseTableName, IndexName,
IndexTypeDesc
FROM sys.dm_os_buffer_descriptors AS bd
INNER JOIN
(
SELECT s_obj.name, s_obj.index_id,
s_obj.allocation_unit_id, s_obj.OBJECT_ID,
i.name IndexName, i.type_desc IndexTypeDesc
FROM
(
SELECT OBJECT_NAME(OBJECT_ID) AS name,
index_id ,allocation_unit_id, OBJECT_ID
FROM sys.allocation_units AS au
INNER JOIN sys.partitions AS p
ON au.container_id = p.hobt_id
AND (au.type = 1 OR au.type = 3)
UNION ALL
SELECT OBJECT_NAME(OBJECT_ID) AS name,
index_id, allocation_unit_id, OBJECT_ID
FROM sys.allocation_units AS au
INNER JOIN sys.partitions AS p
ON au.container_id = p.partition_id
AND au.type = 2
) AS s_obj
LEFT JOIN sys.indexes i ON i.index_id = s_obj.index_id
AND i.OBJECT_ID = s_obj.OBJECT_ID ) AS obj
ON bd.allocation_unit_id = obj.allocation_unit_id
INNER JOIN sys.dm_db_partition_stats s ON s.index_id = obj.index_id AND s.object_id = obj.object_ID
WHERE database_id = DB_ID()
GROUP BY name, obj.index_id, IndexName, IndexTypeDesc
ORDER BY obj.name;
GO
Use this to replace function dbo._GetIndexKeys
(SELECT STRING_AGG(COL_NAME(ic.object_id,ic.column_id), ',') FROM sys.index_columns ic WHERE ic.object_id = so.id AND ic.index_id = si.indid) AS Keys,
--dbo._GetIndexKeys(so.name, si.indid) as Keys,

PostgreSQL query fails over PGNP provider for SQL Server

This query is failing in SQL Server over the PGNP provider:
SELECT 1 AS x
FROM pg_catalog.pg_attribute a
LEFT OUTER JOIN pg_catalog.pg_index i
ON (i.indrelid = a.attrelid
AND a.attnum = i.indkey[a.attnum-1])
This is the error message returned:
The OLE DB provider "PGNP" for linked server "XXX" indicates that either the object has no columns or the current user does not have permissions on that object.
If I run this query directly on the PostgreSQL server with pgAdmin, it returns results. Furthermore, if I remove the clause "a.attnum = i.indkey[a.attnum-1]", the query works over the PGNP provider. (I need this clause in my original query to identify which of a table's columns is the primary key.)
What is the issue, and how do I resolve it?
For the record, this is the complete query that I am executing, from which the query above was excerpted:
SELECT c.relname as table_name, a.attname as column_name
, t.typname as type_name
, i.indisunique AS is_unique_key
, i.indisprimary AS is_primary_key
, CASE t.typname
WHEN 'bpchar' THEN 'char('+CAST(atttypmod - 4 AS VARCHAR)+')'
WHEN 'numeric' THEN 'numeric('+CAST((atttypmod - 4)/65536 AS VARCHAR)
+','+CAST((atttypmod - 4)%65536 AS VARCHAR)
+')'
WHEN 'text' THEN 'varchar(max)'
WHEN 'varchar' THEN 'varchar('+CASE atttypmod WHEN -1 THEN 'max' ELSE CAST(atttypmod-4 AS VARCHAR) END+')'
ELSE t.typname
END as type_name_1
, CAST(CASE atttypmod WHEN -1 THEN NULL ELSE atttypmod - 4 END AS INT4) AS type_precision_scale
FROM pg_catalog.pg_attribute a
JOIN pg_catalog.pg_class c on ( a.attrelid = c.oid)
JOIN pg_catalog.pg_namespace n on (c.relnamespace = n.oid)
JOIN pg_catalog.pg_type t on (a.atttypid = t.oid)
LEFT OUTER JOIN pg_catalog.pg_index i
ON (c.oid = i.indrelid
AND i.indrelid = a.attrelid
AND a.attnum = i.indkey[a.attnum-1])
WHERE c.relkind = 'r' and a.attnum > 0
AND n.nspname = 'public'

SQL Server SP, Function, View source line counter

Is there any utility availble to count the total lines of user created Stored Procedure, Function, Views in a Database?
For SQL Server 2005 and 2008.
This includes all code including blank lines and trailing blank lines, but not the last line (no CRLF). So it's averages out... but it would always be an approximation anyway.
WITH CRLF AS
(
SELECT
CHARINDEX('
', definition) AS CRLF,
SM.[object_ID]
FROM
sys.sql_modules SM
WHERE
OBJECT_NAME([object_ID]) not in ('fn_diagramobjects', 'sp_alterdiagram', 'sp_creatediagram', 'sp_dropdiagram', 'sp_helpdiagramdefinition', 'sp_helpdiagrams', 'sp_renamediagram', 'sp_upgraddiagrams', 'sysdiagrams')
UNION ALL
SELECT
CHARINDEX('
', definition, C.CRLF + 2),
SM.[object_ID]
FROM
sys.sql_modules SM
JOIN
CRLF C ON SM.[object_ID] = C.[object_ID]
WHERE
CHARINDEX('
', definition, C.CRLF + 2) > C.CRLF
)
SELECT
COUNT(*)
FROM
CRLF
OPTION
(MAXRECURSION 0)
Edit:
You may need OBJECTPROPERTY(SM.[object_ID], 'IsMSShipped') = 0 or explicitly exclusions for diagram code etc
Edit 2:
From other solution in otehr answer, corrected to not give "-1" for check constraints and apply same filters/types
select t.sp_name, sum(t.lines_of_code) as lines_ofcode, t.type_desc
from
(
select o.name as sp_name,
(len(c.text) - len(replace(c.text, char(13), ''))) as lines_of_code,
case when o.xtype = 'P' then 'Stored Procedure'
when o.xtype in ('FN', 'IF', 'TF') then 'Function'
end as type_desc
from sysobjects o
inner join syscomments c
on c.id = o.id
where --o.xtype in ('V', 'P', 'FN', 'IF', 'TF', 'TR')
--and
o.category = 0
AND
o.name not in ('fn_diagramobjects', 'sp_alterdiagram', 'sp_creatediagram', 'sp_dropdiagram', 'sp_helpdiagramdefinition', 'sp_helpdiagrams', 'sp_renamediagram', 'sp_upgraddiagrams', 'sysdiagrams')
) t
group by t.sp_name, t.type_desc
order by 1
COMPUTE SUM (sum(t.lines_of_code))
They all give the same results here on several databases. eg 4607 for a SQL Server 2005 SP2 ReportServer database...
Not that I know of, but you could look through the stuff in sysobjects and execute sp_helptext on each proc and view and count the newlines.
If you want a non CTE based solution you could do something like this:
select sum(newlines) from
(
select newlines = (datalength(definition) - datalength(replace(definition, '
', ' '))) / 2 from sys.sql_modules
) as a

Resources