如果您遗失了信息,我会在要求时附上这些信息。
工作区
我有一个在这种MS SQL 2012标准版上运行的数据库:
表:
用户(id,softId(非唯一),生日)
docs(docId,userId,creationDate,deleteDate,lastname,forename,classificationId)
索引:lastname,forename,docId,creationDate,userID(clustered)
注意:在此特定情况下,名称与文档相关,而不是与userId相关
分类(id,description)
三个表“数据”
关系:
用户到文档:1到n
分类到docs:1到n
数据表的文档:1到n
要选择完整的记录,我实际上是在以下陈述中:
服务器执行时间16秒
SELECT * FROM (
select * from docs
where userID in (
select distinct userID from users where softId like '...'
)
) as doc
LEFT JOIN users on users.userID = doc.userId
LEFT JOIN classifications on classifications.id = doc.classificationId
LEFT JOIN data1 on data1.docId = doc.docId
LEFT JOIN data2 on data2.docId = doc.docId
LEFT JOIN data3 on data3.docId = doc.docId;
更新 - 现在15秒
SELECT
docID, calssificationId, classificationDescription,
userId, softId, forename, lastname, birthdate,
data1.id, data1.date, data2.id, data2.date, data3.id, data3.date,
FROM docs
JOIN users on users.userID = doc.userId AND softId like '...'
LEFT JOIN classifications on classifications.id = doc.classificationId
LEFT JOIN data1 on data1.docId = doc.docId
LEFT JOIN data2 on data2.docId = doc.docId
LEFT JOIN data3 on data3.docId = doc.docId;
执行计划
服务器执行时间17秒
DECLARE @userIDs table( id bigint );
DECLARE @docIDs table( id bigint );
insert into @userIDs select userID from users where softId like '...';
insert into @docIDs select docId from docs where userId in ( select id from @userIDs);
SELECT * FROM users where userID in ( select id from @userIDs);
SELECT * FROM docs where docID in (select id from @docIDs);
SELECT * FROM data1 where data1.docId in (select id from @docIDs);
SELECT * FROM data2 where data2.docId in (select id from @docIDs);
SELECT * FROM data3 where data3.docId in (select id from @docIDs);
GO
已更新 - 现在为14秒
DECLARE @userIDs table( id bigint, softId varchar(12), birthdate varchar(8) );
DECLARE @docIDs table( id bigint, classification bigint, capture_date datetime, userId bigint, lastname varchar(50), forename varchar(50) );
INSERT INTO @userIDs select userID, softId, birthdate from users where softId like '...';
INSERT INTO @docIDs select docID, classification, capture_date, userID, lastname, forename from docs where userID in ( select id from @userIDs);
SELECT * FROM @userIDs;
SELECT * FROM @docIDs;
SELECT [only needed fields] FROM data1 where docID in (select id from @docIDs);
SELECT [only needed fields] FROM data2 where docID in (select id from @docIDs);
SELECT [only needed fields] FROM data3 where docID in (select id from @docIDs);
执行计划
常规更新 @AntonínLejsek建议将文档的docId定义为聚簇索引,将pkId定义为非聚簇索引。这改变了执行时间,如下所示:
我再次检查了索引并更改了包含的列,现在它们具有执行时间:
“简单”问题
有人建议减少执行时间吗?
答案 0 :(得分:2)
我会将逻辑说成:
我将摆脱第一个子查询,并在users
表上进行必要的工作:
SELECT *
FROM docs JOIN
users
ON users.userID = doc.userId AND softId LIKE '...' LEFT JOIN
. . .
如果您正在进行IN
,则JOIN
中的逻辑是不必要的。
注意:这可能没什么用,因为您的查询似乎在列和行中都返回了大量数据。
答案 1 :(得分:1)
我在计划中看到两个不同的数据库,我会先尝试在一个数据库中测试它。
数据库设计很奇怪。你有生日的聚集索引。由于它不是唯一的,因此数据库必须组成另一个4B号码才能使其独一无二。所以你在每个非聚集索引中都有12B密钥,这是空间和性能低效的。你甚至没有在非聚集索引中包含id,所以必须查找它,这是浪费时间。在大多数情况下,您应该在主键上进行聚类,这应该是id。
- 已删除 - 虽然softIds几乎是唯一的,但此段落变得无关紧要。
答案 2 :(得分:0)
通过定义主键在表变量上添加聚簇索引。
DECLARE @userIDs table( id bigint primary key, softId varchar(12), birthdate varchar(8) );
DECLARE @docIDs table( id bigint primary key, classification bigint, capture_date datetime, userId bigint, lastname varchar(50), forename varchar(50) );