2014-01-18 5 views
1

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; Есть ли у вас какие-либо предложения?

+0

Трудно поверить, что создание такой функции быстрее, чем индекс в соответствующей реляционной таблице с соответствующим индексом. –

+0

Вещь - это шкала этой третьей реляционной таблицы; это количество строк легко распространяется на миллиарды, где это будет в среднем проверять несколько сотен записей. –

ответ

1

Я начал играть с подстрокой и понял, в чем проблема; смещение инициализируется до 0, когда оно должно быть 1.Изменение этого затем начали правильно возвращать результаты:

declare offset int unsigned default 0; 

должен был:

declare offset int unsigned default 1; 

Однако, смотрите примечание в нижней части первоначального вопроса.

+0

Мои личные мысли об улучшении, по существу, делают вышеизложенное быстрее, сортируя обратный поиск и выполняя двоичный поиск вместо последовательного поиска; Другое полученное предположение также потенциально использовало фильтр цветения в качестве стадии предварительной проверки, однако оба эти метода по-прежнему используют один и тот же поиск в блобе. –

Смежные вопросы