以前我已经要求为我实现sql查询(最初在访问中实现)中必须面对的情况提供可能的解决方案。我已经达成了一个解决方案(经过大量询问后),但我想知道是否有人有其他办法来执行此查询。
我有两个不同的表,一个在sql中,另一个在oracle中(S和O)
O(A,B,C)=> PK =(A,B)和S(D,E,F)=> PK =(D,E)
查询看起来像这样
SELECT A,B,C,E,F
FROM S INNER JOIN O ON
S.D = O.A (Only one attribute of the PK in O)
S有超过10,000个寄存器,O超过7亿个。鉴于此,实现合并连接或查找不是逻辑,因为我将只有D和A之间的第一个匹配。 所以我认为在Oracle方面组装查询会更好。为此,我实施了这样的计划。
使用sql我执行了这个查询:
with tmp(A) as ( select distinct D as A from S
)
select cast( select concat(' or A = ', A)
from tmp
for xml path('')) as nvarchar(max)) as ID
我收到一个字符串,其中包含我要在oracle上搜索的值。 最后在数据流中,我创建了一个这样的表达式:
select A, B, C
from O
where A= '' + @ID
我将这个值下载到sql server然后我可以按照自己的意愿操作它们。
使用foreach循环是必要的,因为我将sql字符串存储在对象变量中。我发现SSIS对nvarchar(max)变量有一些麻烦。
一些注意事项:
1)Oracle数据库是为公司的另一个区域管理的,它们只提供对表的读取权限。
2)sql server的DBA不允许在暂存区域下载O表。不是与他谈判的可能性,此外,这个tabla每天都有更多的登记册更新。他只管理这台服务器,对Oracle没有任何权限。
3)为我团队的一些成员提供的解决方案是在不同的表之间在oracle中创建一个查询,它可以为我提供所需的O属性,因此我可以获得超过3百万的注册并不是所有的属性都是用S表示的。更重要的是,有些D的值已被操纵,所以它们可能不会出现在O中。通过这种实现,我从Oracle获得了超过150,000个寄存器。但我想知道是否可以实现其他解决方案,或者是否有其他组件可以用来达到相同的结果。相信我,当我说我已经阅读,询问和搜索之前,实施这个流程。
答案 0 :(得分:2)
编辑:
选项1(你说你不能使用这个解决方案 - 但它会是第一个 - 最好的)
使用DBLink让Oracle访问S表(必须使用Oracle Database Gateway)。在Oracle中创建一个加入O和S的视图。最后使用链接服务器让SQL Server访问Oracle Joining视图并获得结果。
流程如下:
选项2(你说你不能使用这个解决方案 - 但它会是第二个)
由于你的Oracle管理员似乎是怪物,如果他们抓到你的爪子会杀了你。然后你可以尝试(如果他们让你在oracle中创建一个表):
在Oracle模式中创建一个(临时)表,只有一列(它将存储来自SQL Server的D值)
每次您需要在SQL Server中执行评估查询时执行:
INSERT INTO ORACLE_LINKED_SERVER.ORACLE_OWNER.TEMP_TABLE SELECT SISTINCT D FROM S;
SELECT * FROM OPENQUERY('SELECT * FROM ORACLE_OWNER.O WHERE IN(SELECT D FROM ORACLE_OWNER.TEMP_TABLE)');
最后不要忘记删除Oracle的临时表:
DELETE * FROM ORACLE_LINKED_SERVER.ORACLE_OWNER.TEMP_TABLE;
选项3(如果您拥有Oracle许可证和一个可用主机)
您可以在主机中安装自己的Oracle服务器并使用选项2。
选项4
如果你的解决方案真的是唯一的出路,那么让我们尝试改进一下。
如您所知,您的解决方案有效,但它有点激进(您正在将关系代数半连接运算符转换为具有怪物条件的关系代数选择运算符)。您说每天使用更多寄存器更新Oracle表,但如果表的更新速率低于查询速率,则可以创建可在表S或O未更改时使用的结果缓存。
请按以下步骤操作:
在SQL Server中创建一个表来存储怪物查询的Oracle结果。在构建和启动之前,执行以下命令:
SELECT last_user_update
FROM sys.dm_db_index_usage_stats
WHERE database_id = DB_ID( 'YourDatabaseName')
AND OBJECT_ID=OBJECT_ID('S')
这将返回表S更新的最近时间。将此值存储在表中(创建新表或将此值存储在典型的参数表中)。
创建您的怪物查询。但在启动之前,请将此查询发送给Oracle:
SELECT MAX(ORA_ROWSCN)
FROM O;
它返回导致表中更改的最后一个SCN(系统更改编号)。将此值存储在表中(创建新表或将此值存储在典型的参数表中)。
启动大查询并将其结果存储到缓存表中。
最后,当您需要重复大查询时,首先在SQL Server中执行:
SELECT last_user_update
FROM sys.dm_db_index_usage_stats
WHERE database_id = DB_ID( 'YourDatabaseName')
AND OBJECT_ID=OBJECT_ID('S')
在Oracle中执行:
SELECT MAX(ORA_ROWSCN)
FROM O;
如果一个或两个值相对于您存储在参数表中的值已更改,则必须将它们存储在参数表中(更新旧值)并再次启动大查询。但是,如果没有任何值发生变化,那么您的缓存是最新的,您可以使用它。
请注意