SQL点表示法
SQL dot notation问题的出现原因是因为没有对对象引用进行模式限定。如果对象引用没有进行限定,解析对象引用的方式如下:
1. 在当前数据库的命名空间中查找具有指定名称并属于当前连接所运行的凭据的默认模式的对象。
2. 如果找不到,在当前数据库的命名空间中查找具有指定名称并属于dbo模式的对象。
如果对象引用是以sp_开头的存储过程,情况更糟糕,解析过程中会添加两个步骤(除非引用是数据库限定的):上述两个步骤会重复进行,但这次是在数据库master中查找,而不是在当前数据库中。
这意味着如果有一个查询如下:
select * from foo
需要两次查找命名空间来解析foo(假设表/视图实际上是dbo.foo):首先在默认模式(john_doe.foo)下查找,然后在dbo模式(dbo.foo)下查找。而如果有一个查询如下:
select * from dbo.foo
则只需要一次查找命名空间即可立即解析。
这导致了以下三个问题:
1. 冗余的查找是昂贵的。
2. 它会阻止查询计划缓存,因为每次执行都必须重新评估,这意味着每次执行都必须重新编译查询(这会消耗编译时间锁)。
3. 在某个时候,您或其他人(通常在生产环境中)将在默认模式下意外创建一个本来应该存在于dbo模式下的对象(可能已经存在)。现在,你有两个版本的对象存在。在某个时候,您或其他人(通常在生产环境中)将运行一个查询或执行一个存储过程,然后得到...意外的结果。您需要花费相当长的时间才能发现同一对象有两个[不同]版本,而哪个版本被执行取决于用户凭据以及引用是否进行了模式限定。
除非有真正的理由,否则应始终对模式进行限定。
也可以说,为了开发目的,有时对个人模式下的“新”版本和dbo模式下的“当前”版本进行维护是有用的。这样可以方便进行并行测试。然而,这也不是没有风险的(请参见上文)。
当SQL看到这种语法时,它首先会查看当前用户的模式,看看表是否存在,如果存在则使用该表。如果不存在,则查看dbo模式,并使用那里的表。
这种情况出现的原因是因为在SQL查询中使用了表的简单名称,而没有指定完整的表名(包括模式),导致SQL无法确定要使用哪个模式中的表。
解决这个问题的方法是在查询中明确指定完整的表名,包括模式。可以使用SQL dot notation来指定表的模式,格式为
schema.table
。这样,无论当前用户的模式如何,SQL都能够准确地找到正确的表。
例如,如果要查询dbo模式中的某个表,应该使用
dbo.table
的语法。如果要查询其他模式中的表,可以相应地替换schema的名称。
通过明确指定表的模式,可以避免由于模式不明确而导致的查询错误,确保SQL可以正确地找到和使用所需的表。
问题出现的原因是数据库架构中使用的表名需要使用SQL点表示法(SQL dot notation)进行命名,其中包括三个部分:数据库名称、架构名称和表名称。默认情况下,可以省略架构名称。此外,还可以指定联接服务器名称。
解决方法是根据需要使用不同的SQL点表示法来引用对象名称。可以省略服务器、数据库和所有者的名称,通过在相应的位置使用一个点(.)来标记省略的部分。有效的对象名称包括以下形式:
- server_name.database_name.schema_name.object_name
- server_name.database_name..object_name
- server_name..schema_name.object_name
- server_name...object_name
- database_name.schema_name.object_name
- database_name..object_name
- schema_name.object_name
- object_name
完全限定名称指定了所有四个部分的对象名称。在Microsoft SQL Server中创建的每个对象都必须具有唯一的完全限定名称。大多数对象引用使用三个部分的名称。默认的server_name是本地服务器,default database_name是当前连接的数据库,default schema_name是提交语句的用户的默认架构。除非另有配置,否则新用户的默认架构是dbo架构。
更多关于使用标识符作为表名的信息可以在MSDN上阅读。