Sql 我应该合并这些查询吗?如果是,如何合并?

Sql 我应该合并这些查询吗?如果是,如何合并?,sql,query-optimization,Sql,Query Optimization,我有4张桌子:Foo、Bar、Charlie和Delta。表Charlie、Delta和Bar都有一个外键列,其中包含Foo的主键。外键列具有唯一约束,因此每个列中最多只能有一个链接到给定的Foo。此外,由于域是如何建模的,所以永远不应该同时有一个Charlie和一个Delta链接到同一个Foo 我有一个条,我想知道是否有一个Charlie或Delta链接到相关的Foo,如果没有,那么我需要相关Foo的一些其他数据 目前,我以1-3个查询的形式进行此操作: 获取链接到工具栏的Foo的Charli

我有4张桌子:Foo、Bar、Charlie和Delta。表Charlie、Delta和Bar都有一个外键列,其中包含Foo的主键。外键列具有唯一约束,因此每个列中最多只能有一个链接到给定的Foo。此外,由于域是如何建模的,所以永远不应该同时有一个Charlie和一个Delta链接到同一个Foo

我有一个条,我想知道是否有一个Charlie或Delta链接到相关的Foo,如果没有,那么我需要相关Foo的一些其他数据

目前,我以1-3个查询的形式进行此操作:

获取链接到工具栏的Foo的Charlie的主键(如果有) 如果没有Charlie,则获取链接到该条的Foo的Delta的主键(如果有) 如果没有增量,则从链接到该条的Foo中获取一些其他列 由于历史原因,我们不使用存储过程;每个查询都是在我们正在使用的C代码中构建的,如果这与某些原因有关,那么在可能运行下一个查询之前,它的结果会在那里进行检查

对于Oracle和MS SQL Server 2008,我们都支持这两种查询,单独运行这3个查询还是以某种方式将它们合并到一个查询中更快?如果合并它们的速度更快,我会怎么做

编辑:将每个表视为有两列。Foo有PRIMARY_KEY和OTHER_DATA列,而其他三个表有PRIMARY_KEY和Foo列,其中Foo是一个外键,包含Foo中某行的主键

这3个查询基本上如下所示:

从B栏中选择C.PRIMARY_键,其中B.FOO=C.FOO返回0或1行 从条形图B、Delta D中选择D.PRIMARY_键,其中B.FOO=D.FOO返回0或1行 从B栏中选择F.OTHER_数据,其中B.Foo=F.PRIMARY_键返回1行 是的,将它们结合起来可能会更快。 这是因为你有机会避免多次回到酒吧

当然,很长的答案是,它始终取决于您的索引和硬件设置以及其他一切:。 因此,您必须实际测试旧方法和任何新方法,并寻找显著的改进

既然你说所有这些都是1-1或0-1的关系,我看到的是你真的在为每个Foo记录做一个扩展记录

没有什么能阻止你写作

select
    foo.*       -- of course, specific columns is better
    ,bar.*      -- of course, specific columns is better
    ,c.*        -- of course, specific columns is better
    ,d.*        -- of course, specific columns is better

from
    foo
        inner join bar on foo.pk = bar.fooId
            left join charlie c on bar.fooId = c.fooId
            left join delta d on bar.fooId = c.fooId
我知道,在这种情况下,SQL Server只能一次接触到Bar,从而节省了处理和潜在的磁盘I/O。 因为您对所有内容都使用相同的联接键,这使我更加自信,因为不存在为不同联接重新排序数据的问题。 数据库引擎应该能够很好地将它们相互导入

多个查询应该是一个性能错误,因为Bar被反复读取


在这样一个基本操作中,很可能同样的观点也适用于Oracle,但我不是这方面的专家。

我同意Mike m的观点。每次往返数据库都会显著降低应用程序和数据库的速度。 话虽如此,当您将3个表的结果串在一起时,您可以只往返一次数据库,尽管结果集可能会有点大。 只要Charlie、Delta和Foo表具有相同的列,就可以使用UNION语句组合结果。像这样

SELECT 'Charlie' AS SourceTable, C.PRIMARY_KEY 
FROM Bar B INNER JOIN Charlie C ON B.FOO = C.FOO
UNION
SELECT 'Delta' AS SourceTable, D.PRIMARY_KEY 
FROM Bar B INNER JOIN Delta D ON B.FOO = D.FOO
UNION
SELECT 'Foo' AS SourceTable, F.OTHER_DATA 
FROM Bar B INNER JOIN Foo F ON B.FOO = F.PRIMARY_KEY

否则,Mike M使用左连接的答案也将是一个非常好的选择,只要在其他3个表中没有重复的.foo ID,这将创建笛卡尔乘积=邪恶。您可以通过在Mike M的答案中添加更多WHERE子句来避免这些问题,从而从其他表中筛选出行。

因为您是用C编写代码的,所以可以使用Linq to SQL:

var query = from f in Foo
            // inner equijoin:
            join b in Bar on f.PRIMARY_KEY equals b.FOO
            // left outer join:
            join tc in Charlie on f.PRIMARY_KEY equals tc.FOO into gc
            from c in gc.DefaultIfEmpty()
            // left outer join:
            join td in Delta on f.PRIMARY_KEY equals td.FOO into gd
            from d in gd.DefaultIfEmpty()
            // anonymous object for result set:
            select new {
                Key = f.PRIMARY_KEY,
                Data = f.OTHER_DATA,
                HasCharlie = c == null,
                HasDelta = d == null
            };

                      // get first row with charlie or delta
var resultRow = query.FirstOrDefault(row => row.HasCharlie || row.HasDelta);

if (resultRow == null)
{
                               // get first row, regardless of charlie or delta
    var otherResultRow = query.FirstOrDefault();
}
构建查询也可以通过一系列方法调用来完成:Foo.JoinBar、.GroupJoinCharlie、.SelectMany。。。等等


如果要烘焙查询结果,可以将query.ToList分配给变量,并使用Linq to Objects对该变量执行后续操作,而无需再次访问数据库。或者,如果您将来的操作(如我上面代码中的FirstOrDefault)用于查询,它们将反映在执行代码期间对数据库所做的任何更改。

我们是否可能看到一些SQL?Foo内部连接栏的组合,使用左连接的两个左连接a和左连接B和a可能会起作用。对于初学者,您可以修复连接语法。我不确定人们在哪里仍在接受这方面的教育,但将B.FOO=C.FOO替换为B.FOO=C.FOO上的B.FOO=C.FOO内部连接Charlie C,其中C.fooId为null,d.fooId为null