【发布时间】:2016-09-08 23:06:07
【问题描述】:
我的问题与以下类似:How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?,但我有一些具体问题。
假设我们有这样的表:
| title_id | title | type_id | crit_id |
+----------+----------+---------+---------+
| 1 | title_A1 | 0 | 1111 |
| 2 | title_A2 | 1 | 1111 |
| 3 | title_B1 | 50 | 2222 |
| 4 | title_B2 | 50 | 2222 |
| 5 | title_C1 | 72 | 3333 |
| 6 | title_C2 | 1 | 3333 |
| 7 | title_C4 | 0 | 3333 |
“title_id”是唯一的并被索引,“title”和“crit_id”被索引。
因此,我希望只有按“crit_id”分组的行,保留根据 type_id 计算的自定义排名(优先级)的最小值。 对于等式type_id 的排名如下所示:
type_id = 0 - rank = 10
type_id = 50 -rank = 11
type_id = 1 - rank = 15
type_id = 72- rank = 35
etc...
最后,所有内容都应按“标题”的字母顺序排列 根据要求结果应该是:
| title_id | title | type_id | crit_id | rank |
+----------+----------+---------+---------+------+
| 1 | title_A1 | 0 | 1111 | 10 |
| 3 | title_B1 | 50 | 2222 | 11 |
| 7 | title_C4 | 0 | 3333 | 10 |
我正在使用 SQLITE。我可以通过查询获得所需的结果:
SELECT *, MIN(CASE WHEN type_id = 0 THEN 10
WHEN type_id = 1 THEN 11
WHEN type_id = 50 THEN 15
WHEN type_id = 72 THEN 35
ELSE 1000 END) as rank
FROM titles WHERE ... GROUP BY crit_id ORDER BY title
这个查询的性能真的很差。在 1 000 000 条记录上,它的执行时间超过 10 秒。
这里有几个问题:
- 我们有大约 60% 的记录的 type_id == 0。在这种情况下,我们执行了大约 600 000 次 MIN 和 CASE 子句。由于排名是计算出来的,我们不能在这里使用索引。我想要一些如何最小化它的执行。
- 对如此大量的数据使用 GROUP BY 会带来非常糟糕的性能。在阅读Selecting records holding group-wise maximum (on a unique column) 之后,我不确定它是否总是有正确的行为。希望有另一种方式可以做与 Group By 类似的事情。
PS: 我在嵌入式设备上运行这个,内存卡很慢,因此访问数据库很慢。
我不是 SQL 专家,所以如果有任何解决方案,我将不胜感激。 提前致谢。
忘了说,我们可以LIMIT 应该返回的结果数量。对于等式LIMIT 500.
【问题讨论】:
-
select *和group by几乎从不符合作者的意图。 -
是要在表中排名的 typeid 映射吗?
-
尝试:(1)使用其他
CASE语法,您首先指定要测试的值,然后使用不同的WHEN子句,然后(2)移动MINCASE内部的函数,因此得到:CASE MIN(type_id) WHEN 0 THEN 10 WHEN ... -
当相同的
crit_id值有不同的值时,title_id和其他列应该给出什么?在 SQL 标准中(默认在 MySql 5.7 中应用)你需要以某种方式聚合title_id(例如min(title_id)),或者也按它分组。对于其他在功能上不是由crit_id确定的列也是如此。 -
另外,在 10 秒内从存储卡中查询嵌入式设备上的 1MM 记录听起来并不“非常糟糕”。如果 I/O 或 CPU 是您的瓶颈,那么更改查询可能根本无济于事。
标签: sql performance sqlite group-by min