代码之家  ›  专栏  ›  技术社区  ›  Justin

为什么SQL server不使用我的索引?(过滤连接的索引视图)

  •  4
  • Justin  · 技术社区  · 16 年前

    v_First v_Second . 当我有一个 WHERE 子句,该子句只基于其中一个视图进行筛选,但是,一旦我有了基于这两个视图的筛选条件,我就会得到两次聚集索引扫描,结果性能很差。

    我的问题是:

    SELECT * FROM dbo.v_First (NOEXPAND)
    JOIN dbo.v_Second (NOEXPAND)
    ON dbo.v_First.id = dbo.v_Second.id
    WHERE 
    dbo.v_First.Firstname = 'JUSTIN'
    OR dbo.v_Second.Surname = 'JUSTIN'
    

    哪里 子句,然后我得到查找并执行查询,这样我就知道我已经定义了正确的索引。

    (抱歉,我不能发布执行计划,它们都很简单-只需在两个视图上进行两次聚集索引扫描聚集索引和一个合并连接)

    更新:

    先来看看 柱:

    • ID(bigint,聚集索引)
    • 名字(varchar(254),非聚集索引)

    伏秒

    • ID(bigint,聚集索引)

    所有索引只包含一列。

    更新,第二次:

    OR 子句更改为 AND 子句,则查询执行良好。我还发现,如果将查询更改为使用 UNION 或者

    SELECT * FROM dbo.v_First (NOEXPAND)
    JOIN dbo.v_Second (NOEXPAND)
    ON dbo.v_First.ID = dbo.v_Second.ID
    WHERE dbo.v_First.Firstname = 'JUSTIN'
    UNION SELECT * FROM dbo.v_First (NOEXPAND)
    JOIN dbo.v_Second (NOEXPAND)
    ON dbo.v_First.ID = dbo.v_Second.ID
    WHERE dbo.v_Second.Surname = 'JUSTIN'
    

    据我所知,这两个查询应该是等价的?

    最后,我还发现使用子查询也会产生奇怪的效果,下面的查询执行得很好:

    SELECT * FROM dbo.v_First (NOEXPAND)
    -- JOIN dbo.v_Second (NOEXPAND)
    -- ON dbo.v_First.ID = dbo.v_Second.ID
    WHERE dbo.v_First.ID IN
    (
          SELECT ID FROM dbo.v_Second (NOEXPAND)
          WHERE dbo.v_Second.Surname = 'JUSTIN'
    )
    OR dbo.v_First.Firstname = 'JUSTIN'
    

    但是如果我取消注释 JOIN (这样我就可以从查询结果中的第二个表中获得列)然后对v峈second聚集索引进行表扫描(但是请注意,这仍然比原始查询更好,因为它只涉及1次扫描,而不是2次扫描)。

    我很困惑-怎么回事?似乎我可以通过“重构”我的查询来解决这些问题,但是我担心的是我不理解这里发生了什么——我宁愿避免做出我不完全理解的更改。

    1 回复  |  直到 16 年前
        1
  •  3
  •   gbn    16 年前

    观察

    • 你有一个“或”条件是不可销售的

    • 您可能需要将ID添加到每个索引中,这样就可以在不进行扫描/查找的情况下使用它

    • SET SHOWPLAN_TEXT

    为了回答您的问题,我可能会在基表上有一个索引,同时包含两个文本列,并让它扫描它。OR没有给你很多选项,2个索引视图是没有意义的。更新之后,您有一些人为的SQL结构:您真的需要2个索引视图和一个奇特的派生表或联合吗?