SQL:内部连接两个大型表
我有两个巨大的表,每个表大约有1亿条记录,我担心我需要在这两个表之间执行一个内部连接。现在,两个表都非常简单;以下是描述: 生物实体表:SQL:内部连接两个大型表,sql,sql-server,sql-server-2008,query-optimization,inner-join,Sql,Sql Server,Sql Server 2008,Query Optimization,Inner Join,我有两个巨大的表,每个表大约有1亿条记录,我担心我需要在这两个表之间执行一个内部连接。现在,两个表都非常简单;以下是描述: 生物实体表: 生物实体ID(int) 名称(nvarchar 4000,尽管这是一个过度使用) 类型ID(int) EGM表(事实上,是批量导入操作产生的辅助表): EMGId(内部) PId(整数) 名称(nvarchar 4000,尽管这是一个过度使用) 类型ID(int) 上次修改(日期) 我需要获得一个匹配的名称,以便将BioEntityId与驻留在EGM表
- 生物实体ID(int)
- 名称(nvarchar 4000,尽管这是一个过度使用)
- 类型ID(int)
- EMGId(内部)
- PId(整数)
- 名称(nvarchar 4000,尽管这是一个过度使用)
- 类型ID(int)
- 上次修改(日期)
SELECT EGM.Name, BioEntity.BioEntityId INTO AUX
FROM EGM INNER JOIN BioEntity
ON EGM.name LIKE BioEntity.Name AND EGM.TypeId = BioEntity.TypeId
我已经手动设置了一些索引;EGM和BioEntity都有一个包含TypeId和Name的非聚集覆盖指数。但是,该查询运行了五天,并且也没有结束,因此我尝试运行数据库调优顾问以使其正常工作。它建议删除我以前的索引,并创建统计信息和两个聚集索引(每个表上一个,只包含TypeId,我觉得这很奇怪,或者很愚蠢,但我还是尝试了一下)
它已经运行了6天了,我仍然不知道该怎么办。。。
有什么想法吗,伙计们?我怎样才能使它更快(或者,至少是有限的)
更新:
-好的,我已经取消了查询并重新启动了服务器,以使操作系统重新启动并运行
-我正在使用您建议的更改重新运行工作流,特别是将nvarchar字段裁剪为更小的大小,并将“like”替换为“=”。这至少需要两个小时,所以我稍后会发布更多更新
更新2(格林威治时间2009年11月18日下午1点):
-估计的执行计划显示了67%的表扫描成本以及33%的哈希匹配。接下来是0%并行(这不是很奇怪吗?这是我第一次使用估计执行计划,但这一特殊事实让我大吃一惊),0%哈希匹配,更多0%并行,0%top,0%表插入,最后是另一个0%select into。似乎索引是垃圾,正如预期的那样,所以我将制作手动索引并丢弃垃圾建议索引 对于大型连接,有时明确选择
循环连接
会加快速度:
SELECT EGM.Name, BioEntity.BioEntityId INTO AUX
FROM EGM
INNER LOOP JOIN BioEntity
ON EGM.name LIKE BioEntity.Name AND EGM.TypeId = BioEntity.TypeId
一如既往,公布您的预计执行计划可以帮助我们提供更好的答案
编辑:如果两个输入都已排序(应该是,带有覆盖索引),您可以尝试:
1亿张唱片是巨大的。我想说,要使用这么大的数据库,您需要一个专用的测试服务器。在执行类似的查询时,使用同一台机器做其他工作是不实际的
您的硬件功能相当强大,但要让这么大的连接正常运行,您需要更多的电源。8GB的四核系统将是一个良好的开端。除此之外,您还必须确保索引设置正确。我可能会尝试删除“LIKE”操作符;因为您似乎没有进行任何通配符匹配。我不是SQL调优专家,但在我所知道的任何数据库系统中,在VARCHAR字段上加入数亿行听起来都不是一个好主意
您可以尝试向每个表中添加一个整数列,并在NAME字段上计算一个哈希值,在引擎必须查看实际的VARCHAR数据之前,该哈希值应能将可能的匹配项设置为合理的数字。根据建议,我将对名称进行哈希,以使联接更合理。如果可能的话,我将强烈考虑通过查找查找批处理中的ID分配,因为这将消除以后加入连接的必要性(并且潜在地重复执行这样低效的连接)。 我看到你在TypeID上有这个索引-如果这是有选择性的,这将非常有帮助。此外,将具有名称哈希的列添加到同一索引中:
SELECT EGM.Name
,BioEntity.BioEntityId
INTO AUX
FROM EGM
INNER JOIN BioEntity
ON EGM.TypeId = BioEntity.TypeId -- Hopefully a good index
AND EGM.NameHash = BioEntity.NameHash -- Should be a very selective index now
AND EGM.name LIKE BioEntity.Name
我可能提供的另一个建议是尝试获取数据的子集,而不是一次处理所有100m行来优化查询。这样,您就不必花费太多时间等待查询何时完成。然后你可以考虑检查查询执行计划,它也可以提供对手头问题的一些洞察力。 < P>因为你不要求DB做任何奇特的关系操作,所以你可以很容易地编写这个脚本。尝试导出这两个表(您能从备份中获得脱机副本吗?),而不是通过一个庞大但简单的查询杀死数据库 导出表后,编写一个脚本来执行这个简单的连接。它将花费大约相同的时间来执行,但不会杀死数据库 由于数据的大小和查询运行所需的时间长度,您不会经常这样做,因此脱机批处理是有意义的
对于脚本,您需要为较大的数据集编制索引,然后遍历较小的数据集并查找较大的数据集索引。运行它将是O(n*m)。您有任何主键或索引吗
SELECT EGM.Name
,BioEntity.BioEntityId
INTO AUX
FROM EGM
INNER JOIN BioEntity
ON EGM.TypeId = BioEntity.TypeId -- Hopefully a good index
AND EGM.NameHash = BioEntity.NameHash -- Should be a very selective index now
AND EGM.name LIKE BioEntity.Name
CREATE TABLE BioEntity
(
BioEntityId int
,Name nvarchar(4000)
,TypeId int
,NameLookup AS checksum(Name) persisted
)
CREATE clustered INDEX IX_BioEntity__Lookup on BioEntity (NameLookup, TypeId)
SELECT EGM.Name, BioEntity.BioEntityId INTO AUX
FROM EGM INNER JOIN BioEntity
ON EGM.NameLookup = BioEntity.NameLookup
and EGM.name = BioEntity.Name
and EGM.TypeId = BioEntity.TypeId