视图优化中的子查询
Sub-query within a view optimization
我有一个从两个表 Call
和 Caller
读取的视图,这两个表是并行的,因为它们以相同的 ID 为键(即获取呼叫的呼叫者信息,您加入 Call.id = Caller.id)。我有一个跨越这两个表的视图 return 关于任何特定呼叫或一组呼叫的综合信息。
但我在该视图中有一个子查询,用于确定呼叫者是否已被回叫(定义为在该呼叫后存在另一个对相同 phone 号码的呼叫,状态为的完成)。此子查询使视图的查询速度极慢,但我不确定包含此信息的更好方法是什么。以下是相关的 DDL,想法?
编辑:如果添加了一些索引,这个查询是否会很好,或者是否有更有效的方式来构造查询本身?
CREATE TABLE [CALL]
(
ID VARCHAR(64) PRIMARY KEY, --this is a legacy system, I know varchar(64) isn't an efficient primary key
CALLDATE DATETIME,
STATUS BIT --1 = Complete, 0 = Incomplete
)
CREATE TABLE [CALLER]
(
ID VARCHAR(64) PRIMARY KEY,
PHONENUMBER VARCHAR(10),
FIRSTNAME VARCHAR(50),
LASTNAME VARCHAR(50)
)
CREATE VIEW [CALLVIEW] AS
SELECT
CALL.ID AS CALLID,
CALL.CALLDATE AS CALLDATE,
CALL.STATUS AS CALLSTATUS,
CALLER.PHONENUMBER AS PHONENUMBER,
CALLER.FIRSTNAME AS FIRSTNAME,
CALLER.LASTNAME AS LASTNAME,
CAST(CASE WHEN EXISTS (SELECT TOP 1 1
FROM [CALL] CALL2
INNER JOIN [CALLER] CALLER2 ON CALL2.ID = CALLER2.ID
WHERE CALLER2.PHONENUMBER = CALLER.PHONENUMBER
AND CALL2.CALLDATE > CALL.CALLDATE
AND CALL2.STATUS = 1) THEN 1 ELSE 0 END AS BIT) AS CALLEDBACK
FROM
[CALL]
INNER JOIN [CALLER] ON [CALL].ID = [CALLER].ID
编辑:从执行计划中我注意到,到目前为止,查询中最昂贵的部分如下:
聚集索引查找
谓词:CALL2.CALLDATE > CALL.CALLDATE AND CALL2.STATUS = 1
对象:[CALL].[PK_CALL] CALL2(所以用的是主键索引)
输出列表:[CALL].CALLDATE, [CALL].STATUS
寻找谓词:[CALL].id = 标量运算符([CALLER].id)
索引查找
对象:[CALLER].[IX_PHONENUMBER] CALLER2(所以它使用了正确的索引但仍然很昂贵?)
输出列表:[CALLER].ID
寻找谓词:[CALLER].PHONENUMBER = 标量运算符([CALLER].PHONENUMBER)
首先,尝试使用Database Engine Tuning Advisor,它会告诉您是否需要创建一些索引。
无论如何,我会这样做:
- 验证您在 CALL.ID 和 CALLER.ID 上确实有一个 CLUSTERED 索引(作为遗留系统,也许您有 PK 但有人删除了索引)
- 创建非聚集索引:
- CALLER.PHONENUMBER
- CALL.CALLDATE
- CALL.STATUS
- Reorganize/Rebuild 索引
- 更新统计数据
我有一个从两个表 Call
和 Caller
读取的视图,这两个表是并行的,因为它们以相同的 ID 为键(即获取呼叫的呼叫者信息,您加入 Call.id = Caller.id)。我有一个跨越这两个表的视图 return 关于任何特定呼叫或一组呼叫的综合信息。
但我在该视图中有一个子查询,用于确定呼叫者是否已被回叫(定义为在该呼叫后存在另一个对相同 phone 号码的呼叫,状态为的完成)。此子查询使视图的查询速度极慢,但我不确定包含此信息的更好方法是什么。以下是相关的 DDL,想法?
编辑:如果添加了一些索引,这个查询是否会很好,或者是否有更有效的方式来构造查询本身?
CREATE TABLE [CALL]
(
ID VARCHAR(64) PRIMARY KEY, --this is a legacy system, I know varchar(64) isn't an efficient primary key
CALLDATE DATETIME,
STATUS BIT --1 = Complete, 0 = Incomplete
)
CREATE TABLE [CALLER]
(
ID VARCHAR(64) PRIMARY KEY,
PHONENUMBER VARCHAR(10),
FIRSTNAME VARCHAR(50),
LASTNAME VARCHAR(50)
)
CREATE VIEW [CALLVIEW] AS
SELECT
CALL.ID AS CALLID,
CALL.CALLDATE AS CALLDATE,
CALL.STATUS AS CALLSTATUS,
CALLER.PHONENUMBER AS PHONENUMBER,
CALLER.FIRSTNAME AS FIRSTNAME,
CALLER.LASTNAME AS LASTNAME,
CAST(CASE WHEN EXISTS (SELECT TOP 1 1
FROM [CALL] CALL2
INNER JOIN [CALLER] CALLER2 ON CALL2.ID = CALLER2.ID
WHERE CALLER2.PHONENUMBER = CALLER.PHONENUMBER
AND CALL2.CALLDATE > CALL.CALLDATE
AND CALL2.STATUS = 1) THEN 1 ELSE 0 END AS BIT) AS CALLEDBACK
FROM
[CALL]
INNER JOIN [CALLER] ON [CALL].ID = [CALLER].ID
编辑:从执行计划中我注意到,到目前为止,查询中最昂贵的部分如下:
聚集索引查找
谓词:CALL2.CALLDATE > CALL.CALLDATE AND CALL2.STATUS = 1
对象:[CALL].[PK_CALL] CALL2(所以用的是主键索引)
输出列表:[CALL].CALLDATE, [CALL].STATUS
寻找谓词:[CALL].id = 标量运算符([CALLER].id)
索引查找
对象:[CALLER].[IX_PHONENUMBER] CALLER2(所以它使用了正确的索引但仍然很昂贵?)
输出列表:[CALLER].ID
寻找谓词:[CALLER].PHONENUMBER = 标量运算符([CALLER].PHONENUMBER)
首先,尝试使用Database Engine Tuning Advisor,它会告诉您是否需要创建一些索引。
无论如何,我会这样做:
- 验证您在 CALL.ID 和 CALLER.ID 上确实有一个 CLUSTERED 索引(作为遗留系统,也许您有 PK 但有人删除了索引)
- 创建非聚集索引:
- CALLER.PHONENUMBER
- CALL.CALLDATE
- CALL.STATUS
- Reorganize/Rebuild 索引
- 更新统计数据