提高MS SQL事务性能

时间:2016-10-06 12:18:32

标签: sql sql-server performance sql-server-2012

如果您遗失了信息,我会在要求时附上这些信息。

工作区

我有一个在这种MS SQL 2012标准版上运行的数据库:

  • 表:

    • 用户(id,softId(非唯一),生日)

      • 行:1050万
      • 索引:所有三列,生日(聚集)
    • docs(docId,userId,creationDate,deleteDate,lastname,forename,classificationId)

      • 行:2300万
      • 索引:lastname,forename,docId,creationDate,userID(clustered)

      • 注意:在此特定情况下,名称与文档相关,而不是与userId相关

    • 分类(id,description)

      • 行:200
    • 三个表“数据”

      • 行:10,13和0.3百万
      • 索引:docIds
  • 关系:

    • 用户到文档: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定义为非聚簇索引。这改变了执行时间,如下所示:

  • 加入声明:-1秒
  • Multi-Select-Statement:-5秒

我再次检查了索引并更改了包含的列,现在它们具有执行时间:

  • 加入声明:4秒
  • Multi-Select-Statement:6秒

“简单”问题

有人建议减少执行时间吗?

3 个答案:

答案 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) );