【问题标题】:Using Index for joining two tables when FK field is NULL当 FK 字段为 NULL 时使用索引连接两个表
【发布时间】:2016-02-27 14:23:07
【问题描述】:

我们开始维护一个使用 SQL Server 的新项目,但对于某些表中的数据存在一些问题,如下所述。有 2 个表名为 EmployeePassPass 表保存每个 Employee 的进出。

员工

|| ID       || Name       || CardNo ||
======================================
|| 1        || John       || 101    ||
|| 2        || Christof   || 102    ||
|| 3        || Jurgen     || 103    ||
|| 4        || Jose       || 104    ||
|| 5        || Mary       || 105    ||

通过

|| ID       || EmployeeID || CardNo ||
======================================
|| 1        || NULL       || 101    ||
|| 2        || NULL       || 105    ||
|| 3        || NULL       || 103    ||
|| 4        || NULL       || 101    ||
|| 5        || NULL       || 102    ||
|| 6        || NULL       || 104    ||
|| 7        || NULL       || 104    ||
|| 8        || NULL       || 103    ||
|| 9        || NULL       || 105    ||
|| 10       || NULL       || 101    ||

另一方面,由于Pass 表的EmployeeID 列每次传递都是空的,我们必须使用CardNo 列来连接两个表。

但是使用如下所示的JOIN 子句会导致查询执行更多时间,我认为可能有更好的方法通过使用索引等而不是PK 来优化查询。我们已尝试创建索引,但无法为 CardNo 列创建索引。

能否请您解释一下如何解决该问题?谢谢...

SELECT *  
FROM Pass p
LEFT JOIN Employee e ON RIGHT(e.CardNo, 8) = RIGHT(p.CardNo, 8) --I have to trim card no as the digit sizes are different

更新: 我尝试应用以下脚本,但只有这部分有效:

alter table Pass add cardno8 as RIGHT(CardNo, 8);
alter table Employee add cardno8 as RIGHT(CardNo, 8);

这部分给出了错误:“表'Pass'中的列'cardno8'是一种无效的类型,不能用作索引中的键列。”

create index idx_tEvent_cardno8 ON Pass(cardno8);
create index idx_tEmployee_cardno8 ON Employee (cardno8);

有什么想法吗?

【问题讨论】:

  • "我们已尝试创建索引,但无法为 CardNo 字段创建索引。"为什么不?你收到错误了吗?我看不出你不能创建这样一个索引的明显原因。
  • “我必须修剪卡号,因为数字大小不同” - pass.cardno 不等于对应的employee.cardno?你能举个例子吗?
  • Unfortunatela 卡号保存 11 位给员工,而保存 10 位到 Pass 表前导零。出于这个原因,我不得不取卡号的最后 8 位数字。
  • 您可能必须将cast() right() 函数转换为适当的类型。
  • 你的意思是我只是在查询中强制转换 CardNo 字段而不将其数据类型从 varchar 更改为 int?另一方面,我应该创建您之前建议的索引吗?谢谢。

标签: sql sql-server join indexing common-table-expression


【解决方案1】:

如果问题是查询的性能,那么您只需要在Employee(CardNo) 上建立一个索引:

create index idx_employee_cardno on employee(cardno);

如果您只对其他一两列感兴趣(例如 name 或 id),可以将它们添加到索引中 cardno 之后。

我能想到的(除了权限之外)解释索引创建失败的唯一原因是cardno 的类型错误。引用documentation

大对象 (LOB) 数据类型的列ntexttextvarchar(max)nvarchar(max)varbinary(max)xmlimage 不能 指定为索引的键列。

鉴于样本数据,这似乎不太可能。如果这是一个问题,请将类型更改为更合适的类型(或为相同目的使用计算列)。

此外,您的查询应在任何地方使用合格的列名(否则您会收到错误消息):

SELECT *
FROM Pass p LEFT JOIN
     Employee e
     ON e.CardNo = p.CardNo;
--------^

【讨论】:

  • 非常感谢您的帮助。实际上这个问题与Join multiple tables by multiple grouping 有关,我只是创建了一张单独的票,因为问题不同。所以,我对这个问题的回答投了赞成票,但不幸的是无法创建索引。另一方面,您在那个问题上看到还有另一个问题让我强制使用 RIGHT 函数。
  • 我更新了我上面的问题,能否请你一步一步地澄清我应该遵循哪些程序来解决这个问题?谢谢...
  • 你是对的,问题实际上是 CardNo 字段(Varchar)的数据类型。所以,这意味着如果它是 int,我们可以创建索引并用作 FK,这是真的吗?
  • @hexadecimal 。 . .我认为除了文档中提到的类型之外的任何类型都适合索引。
猜你喜欢
  • 2014-06-15
  • 2022-01-20
  • 1970-01-01
  • 2019-04-03
  • 2013-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多