基于非唯一标识符的MySQL连接

基于非唯一标识符的MySQL连接,mysql,join,Mysql,Join,我有一个如下所示的数据库表 apiRequest table: +-------+-------------+--------------------------------------+----------------+ | id | type | userId | device | +-------+-------------+----------------------------------

我有一个如下所示的数据库表

apiRequest table:

+-------+-------------+--------------------------------------+----------------+
| id    |    type     |                   userId             |     device     |
+-------+-------------+--------------------------------------+----------------+
| 26786 | healthcheck | 7B0BEA35-7D09-4D46-99C0-45EFF7D3F6E8 | NULL           |
| 26788 | root        | 7B0BEA35-7D09-4D46-99C0-45EFF7D3F6E8 | iPhone 6S Plus |
| 26789 | healthcheck | 7B0BEA35-7D09-4D46-99C0-45EFF7D3F6E8 | NULL           |
| 26791 | root        | 7B0BEA35-7D09-4D46-99C0-45EFF7D3F6E8 | iPhone 6S Plus |
| 26792 | healthcheck | 7B0BEA35-7D09-4D46-99C0-45EFF7D3F6E8 | NULL           |
| 26794 | healthcheck | 7B0BEA35-7D09-4D46-99C0-45EFF7D3F6E8 | NULL           |
| 26795 | root        | 054D45BF-8C0D-40D9-9917-12C86C9A1C09 | iPhone 5       |
| 26796 | root        | 054D45BF-8C0D-40D9-9917-12C86C9A1C09 | iPhone 5       |
在所有类型为“root”的请求上,设备字段中存在一个值,但当类型为“healthcheck”时,情况并非如此。此表中的所有条目填充字段userId。userId字段没有唯一的约束

我正在运行一个查询,以获取符合特定条件的所有健康检查,我还希望在获取这些健康检查时返回设备,为此,我需要将健康检查条目中的userId与根条目中的userId进行匹配

下面是一个正常工作的sql查询,尽管它需要很长时间才能运行,因此不可用:

SELECT a.id, a.type, a.userId, b.device 
FROM apiRequest a 
INNER JOIN apiRequest b ON b.userId = a.userId 
WHERE a.type = 'healthcheck' 
AND b.id = ( SELECT max(id) FROM apiRequest c WHERE c.userId = a.userId AND c.type='root' );
它返回所需的结果:

| 26749 | healthcheck | 054D45BF-8C0D-40D9-9917-12C86C9A1C09 | iPhone 5       |
| 26750 | healthcheck | 054D45BF-8C0D-40D9-9917-12C86C9A1C09 | iPhone 5       |
| 26752 | healthcheck | 054D45BF-8C0D-40D9-9917-12C86C9A1C09 | iPhone 5       |
| 26755 | healthcheck | 7B0BEA35-7D09-4D46-99C0-45EFF7D3F6E8 | iPhone 6S Plus |
| 26758 | healthcheck | 7B0BEA35-7D09-4D46-99C0-45EFF7D3F6E8 | iPhone 6S Plus |
| 26762 | healthcheck | 7B0BEA35-7D09-4D46-99C0-45EFF7D3F6E8 | iPhone 6S Plus |
我已经尝试在userId上运行左连接,但是因为类型为root的右表中有许多匹配项,而类型为healthcheck的左表中的每个条目都没有返回我需要的结果

我的目标是:


是找到性能最佳的查询,以选择所有healthcheck类型的条目,并从根类型的条目中包括匹配设备。

我建议以下想法:

在应用聚合函数maxid的同时,使用groupby on field userId执行查询。现在我们有了每个用户ID的maxid

将初始表与id上的查询1的结果联接

SQL代码 它与您的示例等效,但由于没有子选择请求,因此运行速度更快


还可以考虑在参与联接操作的字段上创建索引。

此查询可能会获得更好的性能,因为子选择只需计算一次:

SELECT      a.id, a.type, a.userId, b.device 
FROM        apiRequest a 
LEFT JOIN  (SELECT   userId, MAX(device) device 
            FROM     apiRequest
            WHERE    type = 'root'
            GROUP BY userId) b ON b.userId = a.userId 
WHERE       a.type = 'healthcheck'
但请确保在类型、用户ID和设备上定义了非唯一索引。这可以通过以下语句实现:

CREATE INDEX idx_apirequest_user_device ON apiRequest (type, userId, device);

如果记录为26788的设备与记录为26791的设备不同,同一用户更换了电话或有多部电话,该怎么办?通过查询,您将匹配具有相同设备的给定用户的所有健康检查。这真的是你想要的吗?好问题@trincot。在我的情况下,这永远不会发生。因此,在运行我在示例中显示的查询时,如果得到minid或maxid,这并不重要,但执行效果很差。X的用户ID对于设备将始终具有相同的值。这个问题似乎与优化有关。我强烈建议使用中记录的解释计划功能。我猜你可以通过添加一个适当的索引来加速这个过程。如果您用解释计划的结果更新您的答案,我很乐意帮助您优化它。@John Foley,看看我的答案,我附加了一个sql查询。@John Foley,您为什么有maxid?你想要最新的根设备,对吗?太棒了。表现很好。谢谢。您可以在内部查询中添加where type='root'。是的,如果类型、用户ID和设备上存在索引,那么这可能会稍微有所改进。这样的索引对于外部查询也很有用。所以我更新了我的答案。谢谢@Ivansenko!你为什么叫MAXdevice?我在OP的查询中没有看到任何关于它的信息,也无法从讨论中理解它的必要性。@IvanGritsenko,我是根据我对同一用户询问不同设备的问题的评论来做MAXdevice的,OP说X的用户ID对设备总是有相同的值。。所以我也可以提出MINdevice,这只是一个通过查询将设备放入组中的问题。我知道MySql将允许不使用MAX,但如果可能,我更喜欢ISO SQL。语法需要聚合。谢谢你的额外工作,Ivan。虽然您提供的示例只返回大约一半的结果。根据我正在测试的当前数据,共有6778份健康检查记录。您的查询只返回3477条记录。此外,运行需要0.05秒,而as trincots查询需要0.03秒。我相信这是因为在您的查询中,我们需要从APIRESQUEST表中收集信息3次,而在trincots查询中需要收集信息2次。@John Foley,这可能是因为某些healthchecks没有用户ID对应的类型。您可以尝试将第一个内部连接更改为左连接-将为您提供所有健康检查,但为空。我认为@trincot的查询不会给出与我完全相同的结果。不过,我相信我的查询结果与您的相同。
CREATE INDEX idx_apirequest_user_device ON apiRequest (type, userId, device);