我有一个查询,它将采用一个不同的值列表,并根据排名排序获得第一个匹配,该排序适用于小规模工作。问题在于,当我将其应用于大规模工作时(对40000条记录有35,000条唯一条目),查询只会计时并挂起。
作为一项实验,我只进行了查询的前半部分,在40k行上花了大约3-4分钟(见下文我的意思)。我已经将左连接更改为内部连接,但性能略有提升,但我对其他方法的建议已经不多了。
注意 如果可能的话,我希望尽可能地使用基于SQL的非专有标准,因为我可能会在不久的将来从MS SQL Server更改为MySQL或Oracle,并且我不想做不必要的重写。
查询
SELECT Q.*
FROM (
SELECT
A.name
, B.id
, B.status
, B.rank
FROM TestA A
LEFT JOIN TestB B
ON B.name = A.name
WHERE
B.rank = (
SELECT MIN(B2.rank)
FROM TestB B2
WHERE B.name = B2.name
)
) Q
-- by first half I mean what is above this line here
WHERE
Q.id = (
SELECT MIN(Q2.id)
FROM (
SELECT
A.name
, B.id
, B.status
, B.rank
FROM TestA A
LEFT JOIN TestB B
ON B.name = A.name
WHERE
B.rank = (
SELECT MIN(B2.rank)
FROM TestB B2
WHERE B.name = B2.name
)
) Q2
WHERE Q.name = Q2.name
)
;
架构:测试数据
CREATE TABLE TestA
(`name` varchar(4))
;
INSERT INTO TestA
(`name`)
VALUES
('bob'),
('john'),
('will')
;
CREATE TABLE TestB
(`name` varchar(4), `id` int, `status` varchar(18), `rank` int)
;
INSERT INTO TestB
(`name`, `id`, `status`, `rank`)
VALUES
('bob', 11, 'happy', 1),
('bob', 12, 'active', 1),
('bob', 93, 'inactive', 2),
('bob', 94, 'canceled', 2),
('bob', 95, 'pending deletion', 3),
('john', 32, 'pending activation', 10),
('john', 24, 'inactive', 4),
('will', 555, 'vacation', 5),
('will', 511, 'vacation', 5),
('will', 661, 'on hold', 9)
;
这是我用模式和代码构成的小提琴
答案 0 :(得分:0)
我首先要提到的是你正在加入名称,我假设你没有在这个专栏中添加任何索引(架构没有定义任何索引)。如果您可以在TableA中使用自动增量ID并将其用作TableB中的外键,则使用带ID的连接可以大大加快查询速度。
如果您具有管理员权限,我还建议您在运行查询时在SQL Server Management Studio(SSMS)中运行探查器。您还可以查看声称比SSMS更好的sqlsentry进行性能分析。 http://www.sqlsentry.com/products/plan-explorer/sql-server-query-view(我没有尝试过,但看起来很有希望)。
如果索引有帮助,请告诉我。
答案 1 :(得分:0)
加入一个字符串,如上所述是不好的......那就是说,这个查询应该稍微快一点,并且与SQL Server& MySQL(在Oracle上不确定)。
SELECT A.name, B.id, B.status, B.rank
FROM TestA A
INNER JOIN TestB B
ON A.name = B.name
INNER JOIN (SELECT MIN(id) AS id FROM TestB GROUP BY name) AS MinID
ON B.id = MinID.id
答案 2 :(得分:0)
SELECT
A.name
, B.id
, B.status
, B.rank
FROM TestA A
LEFT JOIN (
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER(PARTITION BY B.id ORDER BY B.rank) rownum
FROM B
) b1
WHERE rownum = 1
) B
ON B.name = A.name
答案 3 :(得分:0)
尝试这样的事情......
SELECT A.Name
,B.ID
,B.[Status]
,B.[Rank]
FROM TestA A
INNER JOIN
(
SELECT name, id, status, rank
,ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY [Rank] ASC) rn
FROM TestB
) B
ON A.Name = B.Name
WHERE B.RN = 1
答案 4 :(得分:0)
这是一个适用于SQL Server和MySQL的版本。可能比使用row_number()
慢一点。
select A.Name,
B1.id,
B1.status,
B1.rank
from TestB as B1
inner join (
select B3.name,
B3.rank,
min(B3.id) as id
from (
select B4.name,
B4.id,
B4.rank
from TestB as B4
inner join (
select min(B6.rank) as rank,
B6.name
from TestB as B6
group by B6.name
) as B5
on B4.name = B5.name and
B4.rank = B5.rank
) as B3
group by B3.Name,
B3.rank
) as B2
on B1.name = B2.Name and
B1.rank = B2.rank and
B1.id = B2.id
inner join TestA as A
on B1.name = A.name