MySQL версии 5.5.35-журналМногие ко многим отношений с обратного поиска
У меня есть исключительно большой набор данных, который состоит из многих-ко-многим, которая тесно связана с людьми по магазинам в торговых точках. Человек может ходить по магазинам во многих сотнях разных торговых точек, и, кроме того, многие тысячи людей могут совершать покупки в любом конкретном магазине. Общее количество людей и торговых точек распространяется на миллионы.
У меня возникла ситуация, когда проверка того, что человек магазина в определенной розетке должен быть быстро разрешен, поэтому я решил использовать обратный поиск; то есть каждая строка «человек» хранит список идентификаторов для магазинов, в которых они совершают покупки. Из-за объема данных считается, что третья таблица отношений неприемлема; то есть тот, который имеет ряд для каждого выхода. Мое предположение заключается в том, что у него будет мало выбора, кроме как производить сканирование таблицы через множество строк.
Чтобы сохранить этот обратный поиск в MySQL, SET также непригоден, поскольку он содержит не более 64 записей, что, конечно, недостаточно в этой ситуации. Итак, я выбрал BLOB, который структурирован как просто блок, содержащий каждый 4-байтовый идентификатор маленького конца.
Но здесь возникает другая проблема; Когда приходит время найти идентификатор выхода в BLOB с использованием SQL, возникают необычные вещи. Из других вопросов, кажется, единственный способ сделать это - использовать 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 в зависимости от того, действительно ли данный покупатель совершает покупки в данной розетке.
В идеале эта функция получит два числа; идентификатор покупателя и идентификатор выхода, однако преобразование выходного идентификатора в блок из 4 байтов младшего байта кажется ненадежным и, в лучшем случае, медленным, поскольку он должен идти через hex (насколько я могу судить). Поэтому вместо этого вызывающая служба предоставляет блок из 4 байтов.
Интересно, что, возвращая storeID сразу после его установки, получается пустая строка. Это тот случай, если тип storeID является varchar, binary или tinyblob; Кажется, что бы то ни было, он возвращает пустую строку.
Так в качестве последнего средства для целей тестирования, вместо этого я попытался это:
set storeID=substring(hex(allShops),offset,8);
Обеспечение того, чтобы компенсировать счетчик был увеличен на 8 на этот раз, а вход ID регулировали в соответствии с. Тем не менее, опять же, он все еще возвращал пустую строку (снова с возвратом storeID сразу после ее установки), хотя данные allShops отличны от нуля.
Редактировать: Хотя я нашел проблему, я не могу не думать, что, возможно, есть лучший подход к обратному поиску в MySQL; Есть ли у вас какие-либо предложения?
Трудно поверить, что создание такой функции быстрее, чем индекс в соответствующей реляционной таблице с соответствующим индексом. –
Вещь - это шкала этой третьей реляционной таблицы; это количество строк легко распространяется на миллиарды, где это будет в среднем проверять несколько сотен записей. –