如何加速这个嵌套查询的性能?

huangapple go评论61阅读模式
英文:

How can I make this nested query mess faster?

问题

我正在从我的SQL Server数据库查询外部Oracle数据库。我知道,没有WHERE子句,大约在55秒内返回约190,000条记录。添加WHERE子句会导致返回时间从30秒到2.5分钟不等。我知道是最后一个内连接(嵌套查询)导致的,因为没有它,返回时间只需大约2秒,但我不知道如何修复它。我在下面发布了原始查询。我尝试将第一个表作为JOBs的子查询,这样我只连接我需要其他信息的jobs,但这没有帮助。

这都是通过一个存储过程调用的。@jobNumber是该存储过程的参数。

英文:

I'm querying an external Oracle database from my SQL Server database. I know, without the WHERE clause it returns about 190,000 records in about 55 seconds. The addition of the where clause causes the return to take anywhere from 30 seconds to 2.5 minutes. I know it's the last inner join (the nested queries) because without it the return only takes about 2 seconds, but I have no idea how I can fix it. I'm posting the original query below. I've tried making the first table a subquery of the JOBs so I'm only joining on the jobs I need the other info on, but that didn't help.

This is all called with a procedure. @jobNumber is a parameter of that procedure

SELECT * FROM OPENQUERY(externaldb,'SELECT
t1.SERIAL,
t3.PART_NUM,
t2.SUFFIX,
t3.JOB,
t2.DESC,
t2.MODEL,
t2.QTY,
t2.UNIT,
t2.LOCATION,
t6.STATUS,
t1.DESTINATION,
t1.ORDER,
t1.PURCHASER,
t1.PHONE,
t1.CUSTOMER_ID
FROM EXTERNALDB.SERIALS t1
INNER JOIN EXTERNALDB.DELIVERIES t2 ON t1.SERIAL = t2.SERIAL
INNER JOIN EXTERNALDB.DESC t3 ON t2.PART_NUM = t3.PART_NUM
INNER JOIN (SELECT PART, STATUS
            FROM (SELECT
                       t4.SUFFIX,
                       t4.STATUS_TYPE,
                       t4.STATUS_DATE,
                       t4.ID,
                       t4.PART_NUM PART,
                       t4.STATUS,
                       ROW_NUMBER()
                            OVER (PARTITION BY t4.PART_NUM
                            ORDER BY
                                 t4.SUFFIX,
                                 t4.STATUS_TYPE,
                                 t4.STATUS_DATE,
                                 t4.ID) RN
                   FROM EXTERNALDB.STATUSES t4) t5
                   WHERE RN = 1) t6 ON t3.PART_NUM = PART
WHERE t3.JOB = '''''+@jobNumber+'''''')

答案1

得分: 1

你或许应该使用CROSS APPLY来获取零件数量的状态,而不是创建行号。例如:

SELECT * FROM OPENQUERY(externaldb, 'SELECT
t1.SERIAL,
t3.PART_NUM,
t2.SUFFIX,
t3.JOB,
t2.DESC,
t2.MODEL,
t2.QTY,
t2.UNIT,
t2.LOCATION,
t6.STATUS,
t1.DESTINATION,
t1.ORDER,
t1.PURCHASER,
t1.PHONE,
t1.CUSTOMER_ID
FROM EXTERNALDB.SERIALS t1
INNER JOIN EXTERNALDB.DELIVERIES t2 ON t1.SERIAL = t2.SERIAL
INNER JOIN EXTERNALDB.DESC t3 ON t2.PART_NUM = t3.PART_NUM
-- SQL Server语法
CROSS APPLY
(
  SELECT TOP 1 Status
  FROM EXTERNALDB.STATUSES
  WHERE PART_NUM = t3.PART_NUM
) T6
-- 或许在Oracle中也能工作
CROSS APPLY
(
  SELECT Status
  FROM EXTERNALDB.STATUSES
  WHERE PART_NUM = t3.PART_NUM
  FETCH FIRST 1 ROWS ONLY
) T6
WHERE t3.JOB = ''' + @jobNumber + '''')

有关Oracle中的TOP的参考链接:https://blogs.oracle.com/sql/post/how-to-select-the-top-n-rows-per-group-with-sql-in-oracle-database

有关Oracle中的CROSS APPLY的参考链接:https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:9530807800346558418

英文:

Maybe instead of create rownumber you should use cross apply to get the status of the number of part. for example

SELECT * FROM OPENQUERY(externaldb,'SELECT
t1.SERIAL,
t3.PART_NUM,
t2.SUFFIX,
t3.JOB,
t2.DESC,
t2.MODEL,
t2.QTY,
t2.UNIT,
t2.LOCATION,
t6.STATUS,
t1.DESTINATION,
t1.ORDER,
t1.PURCHASER,
t1.PHONE,
t1.CUSTOMER_ID
FROM EXTERNALDB.SERIALS t1
INNER JOIN EXTERNALDB.DELIVERIES t2 ON t1.SERIAL = t2.SERIAL
INNER JOIN EXTERNALDB.DESC t3 ON t2.PART_NUM = t3.PART_NUM
-- sintaxis sql server
CROSS APPLY
(
  SELECT TOP 1 Status
  From EXTERNALDB.STATUSES
  Where PART_NUM = t3.PART_NUM
) T6
-- maybe works in oracle
CROSS APPLY
(
  SELECT Status
  From EXTERNALDB.STATUSES
  Where PART_NUM = t3.PART_NUM
  FETCH first 1 rows only
) T6
WHERE t3.JOB = '''''+@jobNumber+'''''')

Reference about top in oracle https://blogs.oracle.com/sql/post/how-to-select-the-top-n-rows-per-group-with-sql-in-oracle-database

Reference about cross apply in oracle https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:9530807800346558418

答案2

得分: 1

最高效的调用链接服务器的方法是通过以下方式:

EXECUTE (...) AT [LINKED_SERVER]

这样查询的整个执行将在远程服务器上进行。SQL Server 只会输出其结果。

供参考:SQL Server: Execute At LinkedServer

第二个好处是参数传递更加清晰。无需拼接字符串。请查看下面的 SQL 示例。

SQL

EXECUTE (N'SELECT
	t1.SERIAL,
	t3.PART_NUM,
	...
	FROM EXTERNALDB.STATUSES t4) t5
	WHERE RN = 1) t6 ON t3.PART_NUM = PART
	WHERE t3.JOB = ?', @jobNumber) AT [externaldb];
英文:

The most performant way to call a linked server is via

EXECUTE (...) AT [LINKED_SERVER]

That way the entire execution of a query will happen on the remote server. SQL Server will just output the result of it.

For the reference: SQL Server: Execute At LinkedServer

The 2nd benefit is that parameters passing is much cleaner. No need to concatenate strings. Check it out below SQL.

SQL

EXECUTE (N'SELECT
	t1.SERIAL,
	t3.PART_NUM,
	...
	FROM EXTERNALDB.STATUSES t4) t5
	WHERE RN = 1) t6 ON t3.PART_NUM = PART
	WHERE t3.JOB = ?',
@jobNumber) AT [externaldb];

huangapple
  • 本文由 发表于 2023年5月25日 21:09:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76332647.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定