SQL:内部连接两个大型表

Joã*_*ira 24 sql sql-server inner-join query-optimization sql-server-2008

我有两个大表,每个表有大约1亿条记录,我担心我需要在两者之间进行内部连接.现在,两张桌子都非常简单; 这是描述:

BioEntity表:

  • BioEntityId(int)
  • 名称(nvarchar 4000,虽然这是一个过度杀手)
  • TypeId(int)

EGM表(一个辅助表,实际上是批量导入操作的结果):

  • EMGId(int)
  • PId(int)
  • 名称(nvarchar 4000,虽然这是一个过度杀手)
  • TypeId(int)
  • LastModified(日期)

我需要获得匹配的名称,以便将BioEntityId与驻留在EGM表中的PId相关联.最初,我尝试使用单个内连接执行所有操作,但查询似乎占用时间太长,数据库的日志文件(在简单恢复模式下)设法咀嚼所有可用磁盘空间(刚刚超过200 GB,当数据库占用18GB)并且等待两天后查询将失败,如果我没有弄错的话.我设法保持日志不会增长(现在只有33 MB),但查询已经连续运行了6天,并且它看起来不会很快就会停止.

我在相当不错的计算机上运行它(4GB RAM,Core 2 Duo(E8400)3GHz,Windows Server 2008,SQL Server 2008)并且我注意到计算机偶尔会每30秒(给予或接受)一次几秒钟.这使得它很难用于其他任何事情,这真的让我感到紧张.

现在,这是查询:

 SELECT EGM.Name, BioEntity.BioEntityId INTO AUX
 FROM EGM INNER JOIN BioEntity 
 ON EGM.name LIKE BioEntity.Name AND EGM.TypeId = BioEntity.TypeId
Run Code Online (Sandbox Code Playgroud)

我手动设置了一些索引; EGM和BioEntity都有一个包含TypeId和Name的非聚集覆盖索引.但是,查询运行了五天,它也没有结束,所以我尝试运行Database Tuning Advisor来使事情发挥作用.它建议删除我的旧索引并创建统计信息和两个聚簇索引(每个表上一个,只包含我发现相当奇怪的TypeId - 或者只是简单的愚蠢 - 但我还是试了一下).

它现在已经运行了6天,我仍然不确定该怎么做......任何想法的人?我怎样才能更快(或者至少有限)?

更新: - 好的,我已取消查询并重新启动服务器以使操作系统重新启动并运行 - 我正在使用您提议的更改重新运行工作流程,特别是将nvarchar字段裁剪为更小的尺寸并交换"like"为"=".这将需要至少两个小时,所以我稍后会发布进一步的更新

更新2(格林尼治标准时间下午1点,2009年11月18日): - 估计的执行计划显示有关表扫描的成本为67%,然后是33%的哈希匹配.接下来是0%的并行性(这不是很奇怪吗?这是我第一次使用估计的执行计划,但这个特殊的事实只是抬起了我的眉毛),0%哈希匹配,0%并行度,0%顶部,0 %table insert和最后另一个0%select into.似乎索引是垃圾,正如预期的那样,所以我将制作手动索引并丢弃糟糕的建议.

Lar*_*tig 17

我不是SQL调优专家,但是在VARCHAR字段上加入数亿行并不是我所知道的任何数据库系统中的好主意.

您可以尝试向每个表添加一个整数列,并在NAME字段上计算一个哈希值,该哈希值应该在引擎必须查看实际的VARCHAR数据之前获得可能的匹配值.


And*_*mar 10

对于巨大的连接,有时明确选择loop join加速:

SELECT EGM.Name, BioEntity.BioEntityId INTO AUX
FROM EGM 
INNER LOOP JOIN BioEntity 
    ON EGM.name LIKE BioEntity.Name AND EGM.TypeId = BioEntity.TypeId
Run Code Online (Sandbox Code Playgroud)

与往常一样,发布您的估计执行计划可以帮助我们提供更好的答案.

编辑:如果两个输入都已排序(它们应该是覆盖索引),您可以尝试MERGE JOIN:

SELECT EGM.Name, BioEntity.BioEntityId INTO AUX
FROM EGM 
INNER JOIN BioEntity 
    ON EGM.name LIKE BioEntity.Name AND EGM.TypeId = BioEntity.TypeId
OPTION (MERGE JOIN)
Run Code Online (Sandbox Code Playgroud)

  • 我现在正在取消查询,让我们看看SQL Server是否可以从死里复活并给我们计划...... (2认同)

Ric*_*kNZ 7

首先,100M行连接根本不合理或不常见.

但是,我怀疑你所看到的糟糕表现的原因可能与INTO条款有关.有了它,您不仅要进行连接,还要将结果写入新表.您对日志文件增长如此巨大的观察基本上是对此的确认.

要尝试的一件事:删除INTO并查看其执行情况.如果性能合理,那么要解决慢速写入问题,应确保数据库日志文件位于与数据不同的物理卷上.如果不是这样,磁头会在读取数据并写入日志时捶打(大量搜索),并且你的性能会崩溃(可能会低至其原来的1/40到1/60) ).


Arv*_*rvo 6

也许有点偏离主题,但是:"我注意到计算机偶尔每隔30秒就会堵塞(给予或接受)几秒钟."

这种行为是廉价RAID5阵列(或可能是单个磁盘)的特征,同时复制(以及您的查询主要复制数据)千兆字节的信息.

有关问题的更多信息 - 您不能将查询分区为更小的块吗?类似以A,B等开头的名称或特定范围内的ID?这可能会大大降低事务/锁定开销.