【问题标题】:Best way to pass large number of values in SQL query?在 SQL 查询中传递大量值的最佳方法?
【发布时间】:2019-07-06 14:53:36
【问题描述】:

我正在制作一个 iOS 应用程序,它利用类似于 tinder 的滑动/匹配功能。我有一个 MySQL 数据库,用于将用户与满足用户搜索条件的人进行匹配。

滑动功能。 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ 我的用户的搜索条件。 我的用户表基础是什么样的。

我使用 php 和 SQL 创建了一个 API 端点,用于在进行更改时更新每个用户的信息,并获取附近所有符合用户搜索条件的用户。

这是获取附近用户的 php 的样子。

$uid        = strval($_GET['uid']);
$lat        = floatval($_GET['lat']);
$lng        = floatval($_GET['lng']);
$minAge     = intval($_GET['minAge']);
$maxAge     = intval($_GET['maxAge']);
$gender     = intval($_GET['gender']);
$radius     = intval($_GET['radius']);
$type       = intval($_GET['type']);

// This SQL statement selects users from the table 'users' so long as 
//they are within x miles of the user's location and within the age 
//range and gender requirements

$sql = "SELECT *,
    (((acos(sin((?*pi()/180)) * sin((`lat`*pi()/180))+cos((?*pi()/180)) * cos((`lat`*pi()/180)) * cos(((?- `lng`)*pi()/180))))*180/pi())*60*1.1515)
    AS distance
    from users having distance<? AND gender=? AND age<? AND age>? AND type=? AND uid<>?"; 

//Bind parameters to the placeholders
mysqli_stmt_bind_param($stmt, "dddiiiiis", $lat, $lat, $lng, $radius, $gender, $maxAge, $minAge, $type, $uid);

//Run parameters inside database
mysqli_stmt_execute($stmt);

发出此请求的 URL 可能如下所示:

https://mywebsitename.com/getNearbyUsers.php?uid=4pW2I1gpq5VHCHEdm0aEfTRgJO92&lat=38.461822509765625&lng=-90.32567239374883&minAge=18&maxAge=100&gender=2&radius=50&type=3

我的问题:

现在,每当用户 (user1) 在另一个用户 (user2) 上向右或向左滑动时,我想跟踪这个 user2 是否已经呈现给 user1,以便将来不会出现。

我最初打算做什么:

解决这个问题的第一个想法是在我的 SQL 数据库中创建另一个列,该列本质上是一个 uid 数组,用于传达哪些用户已经显示给当前用户。每当前端的用户 (user1) 向右或向左滑动另一个用户的配置文件 (user2) 时,user2 的 uid 就可以添加到 user1 已经刷过的用户数组中。然后,我可以在 SQL 语句中说只返回不在当前用户的 uid 的“alreadyPresentedWith”列中的用户。

问题: 我研究过在 SQL 中引用大量值,发现关系数据库中每列的值不应超过一个。但是,以我给定的技能和经验,这是我能想象完成这项任务的唯一方法。

我只是希望获得更多经验丰富的 php/SQL 开发人员的反馈,告诉我哪个方向最适合我解决这类问题。

【问题讨论】:

  • 如果您要添加另一个 而不是“我的 SQL 数据库中的另一列”怎么办?两列,“用户 A”和“用户 B”,每个刷过“用户 B”的“用户 A”都有一行。然后你会使用子查询过滤掉。
  • 手机接缝上的滑动是否有序?只需使用手机中的本地存储来保护滑动 ID,并在您获取下一组可能的滑动时使用基于(大于 MAX(swipe_id))的过滤器..
  • @RaymondNijland 我考虑过这样做,但根据用户在搜索中传递的搜索条件,返回的顺序可能会改变。在这种情况下,我觉得最好在后端解决所有问题。
  • “我考虑过这样做,但根据用户在搜索中传递的搜索条件,返回的顺序可能会改变。”注意到..返回顺序已经是非确定性的(随机的),因为您没有包含确定性的ORDER BY,其中至少一列具有主键或唯一键.. 非唯一值上的ORDER BY 将给出非确定性绑定值的(随机)结果。

标签: php mysql sql rest


【解决方案1】:

您应该有一个表格,例如swipes,每个操作一行。说:

create table swipes (
    swipes_id int auto_increment primary key,
    swiper_uid binary(16),
    swipee_uid binary(16),
    action varchar(5),  -- 'left', 'right', 'none'
    created_at datetime default now(),
    foreign key (swiper_uid) references persons(uid),
    foreign key (swipee_uid) references persons(uid)
);

从 OP 编辑​​ 所以,解决方案很简单。我按照建议制作了滑动表,创建了一个 API 端点,每次滑动时都会在表中插入“滑动”(在我的情况下,我们不需要存储用户是向左还是向右滑动),然后更新我的端点中获取附近用户的 SQL 语句。

在 SQL 语句中,我添加了一个 NOT EXISTS 检查以引用 swipe 表,并检查条目是否将当前用户作为“swiper”以及查询返回的用户作为“swipee”。这就是获取附近用户的 php 文件中的准备好的语句现在的样子。

$sql = "SELECT *,
(((acos(sin((?*pi()/180)) * sin((`lat`*pi()/180))+cos((?*pi()/180)) * cos((`lat`*pi()/180)) * cos(((?- `lng`)*pi()/180))))*180/pi())*60*1.1515)
AS distance
from users having distance<? AND gender=? AND age<? AND age>? AND type=? AND uid<>? AND NOT EXISTS(SELECT NULL
                FROM swipes s
               WHERE s.swiperUid=? AND u.uid=s.swipeeUid)"; 

//Bind parameters to the placeholders
mysqli_stmt_bind_param($stmt, "dddiiiiiss", $lat, $lat, $lng, $radius, $gender, $maxAge, $minAge, $type, $uid, $uid);

【讨论】:

  • 这似乎是处理大型数据集(在本例中为 uid)的共识。将用户刷过的每个人作为 URL 请求中的参数传递是不合理的,因此我们只需创建另一个表并交叉引用这两者。我想这就是 SQL 的“JOIN”语法派上用场的地方?
  • 不合理,几乎不可能。浏览器对 URL 长度和 RDBMS 对 SQL 查询长度施加了大小限制。
  • @DavidChopin 。 . .不仅是JOIN 语法,还有优化查询的关系数据库的底层机制。
  • @GordonLinoff 好的,太好了。我很感激反馈。我首先是前端开发人员,并且只涉足后端的东西。我会研究你提出的建议,如果我发现任何成功,我会回复。
  • 这个 MySQL 代码中的 uuid 数据类型是什么?您现在正在将 MySQL 与 PostgreSQL 数据类型混合在一起吗?还是说 SQL 是伪代码?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-14
  • 2013-06-10
  • 1970-01-01
  • 2014-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多