MySQL版本5.5.35-log
我有一个非常大的数据集,其中包含多对多关系,这与在网点购物的人密切相关。一个人可以在数百个不同的商店购物,同样地,成千上万的人可以在任何特定商店购物。人员和网点的总数达到数百万。
我的情况是检查一个人在特定商店购物是否必须快速解决,所以我选择使用反向查询;即,每个“人”行存储他们所购商店的ID列表。由于数据量大,第三关系表被认为是不合适的;即每个人出口有一排的人。我的假设是,除了通过许多行产生表扫描之外别无选择。
要在MySQL中存储此反向查找,SET也不适合,因为它最多有64个条目,在这种情况下当然不够。所以,我选择了一个BLOB,它只是一个包含每个4字节little-endian ID的块。
但是,这里出现了另一个问题;当需要使用SQL查找BLOB中是否包含插座ID时,会发生异常事件。从其他问题来看,似乎唯一的方法是在循环中使用带有BLOB的SUBSTRING,但这似乎不起作用; 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
出于调试目的,它被设置为返回一个字符串。意图是它返回真或假,取决于给定的购物者是否在给定的商店购物。
理想情况下,此功能会收到两个数字; shopperID和outletID,但是将outletID转换为4个小端字节的块似乎是不可靠的,并且最好是缓慢的,因为它必须通过十六进制(据我所知)。因此,调用服务提供了4个字节的块。
有趣的是,在设置后立即返回storeID会导致空字符串。如果storeID的类型是varchar,binary或tinyblob,则会出现这种情况。似乎无论如何,它都会返回一个空白字符串。
因此,作为测试目的的最后手段,我改为尝试了这个:
set storeID=substring(hex(allShops),offset,8);
确保此次偏移计数器增加8,并调整输入ID以适应。尽管如此,它仍然返回一个空字符串(在设置后立即返回storeID),即使allShops数据非零。
编辑:虽然我发现了这个问题,但我不禁想到,在MySQL中可能有更好的方法来反向查找这样的查找;你有什么建议吗?
答案 0 :(得分:1)
我开始玩子串,并意识到问题所在;当offset应该为1时,偏移量被初始化为0.更改此值然后开始正确返回结果:
declare offset int unsigned default 0;
应该是:
declare offset int unsigned default 1;
但是,请参阅原始问题底部的注释。