我想改进我当前的查询。我有一个叫做Incomes
的表。这里有一个sourceId
varchar字段。对于我需要的字段,我有一个SELECT,但是我需要添加一个名为isFirstTime
的额外字段来表示它是否第一次在行上使用sourceId
。这是我当前的查询:
SELECT DISTINCT
`income`.*,
CASE WHEN (
SELECT
`income2`.id
FROM
`income` as `income2`
WHERE
`income2`."sourceId" = `income`."sourceId"
ORDER BY
`income2`.created asc
LIMIT 1
) = `income`.id THEN true ELSE false END
as isFirstIncome
FROM
`income` as `income`
WHERE `income`.incomeType IN ('passive', 'active') AND `income`.status = 'paid'
ORDER BY `income`.created desc
LIMIT 50
查询工作,但减慢如果我不断增加LIMIT
或OFFSET
。有什么建议吗?
更新1:增加了用于原始查询的WHERE语句
更新2:MYSQL版本5.7.22
可以使用有序解析函数来实现。
您可以使用ROW_NUMBER
或RANK
来获得所需的结果。
下面的查询将给出所需的输出。
SELECT *,
CASE
WHEN Row_number()
OVER(
PARTITION BY sourceid
ORDER BY created ASC) = 1 THEN true
ELSE false
END AS isFirstIncome
FROM income
WHERE incomeType IN ('passive', 'active') AND status = 'paid'
ORDER BY created desc
DB Fiddle:查看这里的结果
我的第一个想法是isFirstIncome
应该是表中的一个额外列。它应该在数据插入时填充。
如果你不喜欢,让我们试着优化查询…
让我们避免执行子查询超过50次。这需要将查询从内到外翻转。(这就像"爆炸-内爆"一样,查询会收集大量内容,然后对其进行排序,并将大多数行丢弃。)
总结:
-
只需识别5行即可。
-
JOIN到任何需要的表(包括自己,如果合适的话);这是为了获得所需的任何其他列(包括
isFirstIncome
)。SELECT i3.*, ( ... using i3 ... ) as isFirstIncome FROM ( SELECT i1.id, i1.sourceId FROM `income` AS i1 WHERE i1.incomeType IN ('passive', 'active') AND i1.status = 'paid' ORDER BY i1.created DESC LIMIT 50 ) AS i2 JOIN income AS i3 USING(id) ORDER BY i2.created DESC -- yes, repeated
(我省略了isFirstIncome的计算;在其他答案中讨论过。但请注意,它最多将执行50次。)
(别名——i1, i2, i3——按照它们将被"使用"的顺序编号;(这是为了帮助执行SQL.)
辅助性能,添加
INDEX(status, incomeType, created, id, sourceId)
它应该对我的公式有帮助,但可能对其他版本没有帮助。您的版本将受益于
INDEX(sourceId, created, id)