MySQL 版本 5.5.35-日志
我有一个非常大的数据集,其中包含与在奥特莱斯购物的人密切相关的多对多关系。一个人可能在数百个不同的商店购物,同样,成千上万的人可能在任何特定商店购物。总人数和网点均达到数百万。
我有一种情况,必须快速解决检查某人是否在特定商店购物的问题,所以我选择使用反向查找;即每个“人”行存储他们购物的商店的 ID 列表。由于数据量大,第三个关系表被认为是不合适的;即每个人的网点都有一排。我在这里的假设是,它别无选择,只能对很多很多行进行表扫描。
然而,要在 MySQL 中存储这种反向查找,SET 也不合适,因为它最多有 64 个条目,这在这种情况下当然是不够的。因此,我选择了一个 BLOB,它的结构只是一个包含每个 4 字节小端 ID 的 block 。
但是,这里出现了一个不同的问题;当需要使用 SQL 查找 BLOB 中是否包含导出 ID 时,异常情况开始发生。从其他问题来看,似乎唯一的方法是在循环中使用 SUBSTRING 和 BLOB,但这似乎不起作用; SUBSTRING 正在返回一个空字符串。首先,这是一些代码:
CREATE FUNCTION `DoesShopAt`(shopperID INT UNSIGNED,outletID TINYBLOB) RETURNS VARCHAR(20)
BEGIN
-- Setup a loop. We're going to loop through each ID in the blob:
declare i_max int unsigned default 0;
declare i int unsigned default 0;
declare offset int unsigned default 0;
declare storeID tinyblob;
-- Setup the blob store - all the stops a particular shopper goes to:
declare allShops blob;
-- Grab the set of ID's - a blob of each 4 byte outlet ID:
select AllStores from Shoppers where ID=shopperID into allShops;
-- How many shops?
select length(allShops)/4 into i_max;
while i < i_max do
-- Grab the shops ID:
set storeID=substring(allShops,offset,4);
if outletID = storeID then
return "Yep, they do!";
end if;
-- Update the ID offset in the blob:
set offset=offset+4;
-- Update the loop counter:
set i=i+1;
end while;
return "Nope, they don't.";
END
出于调试目的,它被设置为返回一个字符串。目的是根据给定的购物者是否在给定的商店购物而返回 true 或 false。
理想情况下,此函数将接收两个数字; shopperID 和 outletID,但是将 outletID 转换为 4 个小端字节的 block 似乎不可靠且充其量也很慢,因为它必须通过十六进制(据我所知)。因此,调用服务改为提供 4 字节的 block 。
有趣的是,在设置后立即返回 storeID 会导致空字符串。如果 storeID 的类型是 varchar、binary 或 tinyblob,就会出现这种情况;似乎无论如何,它都返回一个空字符串。
因此,作为测试目的的最后手段,我尝试了这个:
set storeID=substring(hex(allShops),offset,8);
确保这次偏移量计数器增加了 8,并且调整了输入 ID 以适应。尽管如此,它仍然返回一个空字符串(再次在设置后立即返回 storeID),即使 allShops 数据不为零。
编辑: 虽然我发现了这个问题,但我还是忍不住想也许在 MySQL 中有更好的方法来进行这样的反向查找;你有什么建议吗?
最佳答案
我开始研究子字符串并意识到问题所在;偏移量在应该为 1 时被初始化为 0。更改此设置然后开始正确返回结果:
declare offset int unsigned default 0;
应该是:
declare offset int unsigned default 1;
但是,请参阅原始问题底部的注释。
关于mysql - 具有反向查找的多对多关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21211296/