【问题标题】:cross database query only works one way MS SQL Server跨数据库查询仅适用于 MS SQL Server 的一种方式
【发布时间】:2014-02-11 16:47:57
【问题描述】:

我正在尝试将有关索引使用情况的数据插入到各种控制数据库中。我正在使用的查询如下。我遇到的问题是,当我从控制数据库执行查询时(我们称之为 A)它返回 0 个结果,但如果我从源数据库执行它(让我们称之为 B)它运行得很好..
为什么?

在 SQL Server 2012 DEV 和 SQL Server 2008 EE 上都可以看到此行为。

示例 1 返回零结果:

USE A;

INSERT INTO A.dbo.UnusedIndexes
SELECT 
    DB_NAME() AS DatabaseName
    , SCHEMA_NAME(o.Schema_ID) AS SchemaName
    , OBJECT_NAME(o.object_id) AS TableName
    , ix.name AS IndexName
    ,((SUM(ps.used_page_count)over(partition by ix.index_id))*8)/1024 AS [IndexSizeMB]
    , ix_usage_stats.user_updates
    , ix_usage_stats.user_seeks + ix_usage_stats.user_scans + ix_usage_stats.user_lookups
                            AS [User_SeeksScansLookups]
    , ix_usage_stats.system_updates                         
    , ix_usage_stats.system_seeks + ix_usage_stats.system_scans + ix_usage_stats.system_lookups
                            AS [System_SeeksScansLookups]
    , NULL as [Drop_Statement]
    , NULL as [Create_statement]
    ,getdate() as [date_added]
    
    
FROM B.sys.indexes ix
Left join B.sys.dm_db_index_usage_stats ix_usage_stats
 ON ix_usage_stats.object_id = ix.object_id
    AND ix_usage_stats.index_id = ix.index_id
INNER JOIN B.sys.objects o ON ix.object_id = o.object_id
JOIN B.sys.dm_db_partition_stats ps ON ps.object_id = ix.object_id AND ix.index_id = ps.index_id
WHERE 
    ix.name IS NOT NULL -- exclude heaps
    AND ix.type <> 1 -- exclude the clustered indexes
    AND o.is_ms_shipped = 0 -- exclude system objects
    AND o.type NOT IN('F', 'UQ') -- exclude the foreign keys and unique contraints
    AND SCHEMA_NAME(o.schema_id) not in ('dbo','stats', 'reporting') 
    AND (ix_usage_stats.user_seeks = 0 or ix_usage_stats.user_seeks is NULL)
    AND (ix_usage_stats.user_scans = 0 or ix_usage_stats.user_scans is null)
    AND (ix_usage_stats.user_lookups = 0 or ix_usage_stats.user_lookups is null)

示例 2 返回预期结果,填充 A.dbo.UnusedIndexes:

USE B;
INSERT INTO A.dbo.UnusedIndexes
SELECT 
    DB_NAME() AS DatabaseName
    , SCHEMA_NAME(o.Schema_ID) AS SchemaName
    , OBJECT_NAME(o.object_id) AS TableName
    , ix.name AS IndexName
    ,((SUM(ps.used_page_count)over(partition by ix.index_id))*8)/1024 AS [IndexSizeMB]
    , ix_usage_stats.user_updates
    , ix_usage_stats.user_seeks + ix_usage_stats.user_scans + ix_usage_stats.user_lookups
                            AS [User_SeeksScansLookups]
    , ix_usage_stats.system_updates                         
    , ix_usage_stats.system_seeks + ix_usage_stats.system_scans + ix_usage_stats.system_lookups
                            AS [System_SeeksScansLookups]
    , NULL as [Drop_Statement]
    , NULL as [Create_statement]
    ,getdate() as [date_added]
    
    
FROM B.sys.indexes ix
Left join B.sys.dm_db_index_usage_stats ix_usage_stats
 ON ix_usage_stats.object_id = ix.object_id
    AND ix_usage_stats.index_id = ix.index_id
INNER JOIN B.sys.objects o ON ix.object_id = o.object_id
JOIN B.sys.dm_db_partition_stats ps ON ps.object_id = ix.object_id AND ix.index_id = ps.index_id
WHERE 
    ix.name IS NOT NULL -- exclude heaps
    AND ix.type <> 1 -- exclude the clustered indexes
    AND o.is_ms_shipped = 0 -- exclude system objects
    AND o.type NOT IN('F', 'UQ') -- exclude the foreign keys and unique contraints
    AND SCHEMA_NAME(o.schema_id) not in ('dbo','stats', 'reporting') 
    AND (ix_usage_stats.user_seeks = 0 or ix_usage_stats.user_seeks is NULL)
    AND (ix_usage_stats.user_scans = 0 or ix_usage_stats.user_scans is null)
    AND (ix_usage_stats.user_lookups = 0 or ix_usage_stats.user_lookups is null)

这整天都有效:

USE A;
Select * from B.sys.indexes 

任何帮助都会很好 - 不幸的是我无法从数据库 B 执行此操作,因此简单的解决方案将不起作用。


已解决

想通了。 DB_NAME() 是问题所在。删除它并将其设置为“B”作为数据库名称解决了这个问题。

【问题讨论】:

  • 您知道DB_NAME() 将返回您当前上下文数据库的名称,而不是您在FROMJOIN 子句中指定的数据库。在您的第一个示例中,即使您从 B 获取数据,您也会返回 A
  • 您是否尝试过删除您的 INSERT INTO A.dbo.UnusedIndexes 语句并验证两个查询是否返回相同的结果?
  • 我明白这一点 - 但即使在查询中使用 DB_NAME() 时,它也会在从 A 执行时返回 0 行
  • 是的-我尝试过选择-但这也不起作用..但我刚刚想通了-感谢您对 DB_NAME() 的评论..将其设置为常数可以解决问题.
  • 验证数据库的表是否有某种限制?

标签: sql sql-server database sql-server-2008 tsql


【解决方案1】:

尝试使用目标数据库中的 sp_executesql:

USE A;

INSERT INTO A.dbo.UnusedIndexes
EXEC B.sys.sp_executesql N'
SELECT DB_NAME() AS DatabaseName
    ,SCHEMA_NAME(o.Schema_ID) AS SchemaName
    ,OBJECT_NAME(o.object_id) AS TableName
    ,ix.NAME AS IndexName
    ,((SUM(ps.used_page_count) OVER (PARTITION BY ix.index_id)) * 8) / 1024 AS [IndexSizeMB]
    ,ix_usage_stats.user_updates
    ,ix_usage_stats.user_seeks + ix_usage_stats.user_scans + ix_usage_stats.user_lookups AS [User_SeeksScansLookups]
    ,ix_usage_stats.system_updates
    ,ix_usage_stats.system_seeks + ix_usage_stats.system_scans + ix_usage_stats.system_lookups AS [System_SeeksScansLookups]
    ,NULL AS [Drop_Statement]
    ,NULL AS [Create_statement]
    ,getdate() AS [date_added]
FROM sys.indexes ix
LEFT JOIN sys.dm_db_index_usage_stats ix_usage_stats
    ON ix_usage_stats.object_id = ix.object_id
        AND ix_usage_stats.index_id = ix.index_id
INNER JOIN sys.objects o
    ON ix.object_id = o.object_id
JOIN sys.dm_db_partition_stats ps
    ON ps.object_id = ix.object_id
        AND ix.index_id = ps.index_id
WHERE 1 = 1
    AND ix.name IS NOT NULL -- exclude heaps
    AND ix.type <> 1 -- exclude the clustered indexes
    AND o.is_ms_shipped = 0 -- exclude system objects
    AND o.type NOT IN(''F'', ''UQ'') -- exclude the foreign keys and unique contraints
    AND SCHEMA_NAME(o.schema_id) not in (''dbo'',''stats'', ''reporting'') 
    AND (
        ix_usage_stats.user_seeks = 0
        OR ix_usage_stats.user_seeks IS NULL
        )
    AND (
        ix_usage_stats.user_scans = 0
        OR ix_usage_stats.user_scans IS NULL
        )
    AND (
        ix_usage_stats.user_lookups = 0
        OR ix_usage_stats.user_lookups IS NULL
        )
'

【讨论】:

猜你喜欢
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-17
  • 2021-12-05
相关资源
最近更新 更多