在sql server中运行两个类似的sqls,其中表TBSFA_DAT_CUST具有毫秒行且没有约束(没有索引和主键), 另外两个只有几行和普通主键:
对于较慢的一个:
SELECT A.CUST_ID, C.CUST_NAME, A.xxx --and several specific columns
FROM TBSFA_DAT_ORD_LIST A JOIN VWSFA_ORG_EMPLOYEE B ON A.EMP_ID = B.EMP_ID
LEFT JOIN TBSFA_DAT_CUST C ON A.CUST_ID = B.CUST_ID
JOIN VWSFA_ORG_EMPLOYEE D ON A.REVIEW_ID = D.EMP_ID
WHERE ISNULL(A.BATCH_ID, '') != ''
f表示速度更快:
SELECT *
FROM TBSFA_DAT_ORD_LIST A JOIN VWSFA_ORG_EMPLOYEE B ON A.EMP_ID = B.EMP_ID
LEFT JOIN TBSFA_DAT_CUST C ON A.CUST_ID = B.CUST_ID
JOIN VWSFA_ORG_EMPLOYEE D ON A.REVIEW_ID = D.EMP_ID
WHERE ISNULL(A.BATCH_ID, '') != ''
f(大于0.6s)比s(大于4.6s)快得多。
否则,我找到了两种方法来快速进行f:
1.在表TBSFA_DAT_CUST.CUST_ID中添加constaint和primary key;
2.特定超过61列表TBSFA_DAT_CUST(共80列)。
我的问题是为什么sql优化器在SELECT子句中的特定列而不是'*'时使用Table Spool,为什么使用Table Spool执行得更慢?
我的问题是关于sql-server table-spool
答案 0 :(得分:0)
在较慢的查询中,您将结果集限制为特定列。由于这是一个未索引的非约束表,优化器正在从原始表扫描创建一个临时表,只需要所需的特定列。然后它通过临时表上的嵌套循环运算符运行。当它知道它需要表上的每一列(Select *)时,它可以直接在表扫描中运行嵌套循环操作符,因为扫描的结果集将完全连接到顶层表。
除此之外,您的查询还有其他一些问题:
LEFT JOIN TBSFA_DAT_CUST C ON A.CUST_ID = B.CUST_ID
你在这里没有加入任何东西,你将整个表加入到每一条记录中。是a.cust_id = c.cust_id
还是b.cust_id = c.cust_id
还是a.cust_id = c.cust_id and b.cust_id = c.cust_id
?
此外,where子句中的此函数毫无意义,可能会降低性能:
WHERE ISNULL(A.BATCH_ID, '') != ''
将其更改为:
WHERE A.BATCH_ID is not null and A.Batch_ID <> ''