У меня есть таблица ограничений по регионам для кодов товаров. Код продукта не имеет фиксированной длины, но может варьироваться от 10 до 25 номеров. Ограничение может содержать префикс продукта, так что все продукты из этого диапазона будут запрещены.
Используемая БД - это MariaDB / Mysql, и вот определение таблицы:
CREATE TABLE product_restrict (
`id` VARCHAR(25) NOT NULL,
`region` VARCHAR(3) NOT NULL,
`from_dttm` DATETIME NOT NULL,
`to_dttm` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`region`, `id`, `from_dttm`))
ENGINE = InnoDB;
В данный момент я использую 15 запросов, определяемых длиной кода целевого продукта, поэтому я могу найти все префиксы, поэтому в моем коде у меня 15 запросов, подобных этому:
SELECT *
FROM product_restrict
WHERE
region='XXX' AND
(
id = "9" OR
id = "98" OR
id = "987" OR
id = "9876" OR
id = "98765" OR
id = "987654" OR
id = "9876543" OR
id = "98765432" OR
id = "987654321" OR
id = "9876543210" OR
id = "98765432109" OR
id = "987654321098" OR
id = "9876543210987" OR
id = "98765432109876" OR
id = "987654321098765" OR
id = "9876543210987654"
) AND (
now() >= from_dttm AND
( now() < to_dttm OR to_dttm is null)
);
SELECT *
FROM product_restrict
WHERE
region='XXX' AND
(
id = "9" OR
id = "98" OR
id = "987" OR
id = "9876" OR
id = "98765" OR
id = "987654" OR
id = "9876543" OR
id = "98765432" OR
id = "987654321" OR
id = "9876543210" OR
id = "98765432109" OR
id = "987654321098" OR
id = "9876543210987" OR
id = "98765432109876" OR
id = "987654321098765" OR
id = "9876543210987654" OR
id = "98765432109876543"
) AND (
now() >= from_dttm AND
( now() < to_dttm OR to_dttm is null)
);
В этой таблице содержится около 100 миллионов записей. У меня вопрос, есть ли способ свести это к одному запросу с той же производительностью выбора? Изменение структуры таблицы, к сожалению, вне моей власти.
Отредактировано после подсказки INSTR () от @Pham X. Бах:
Я провел несколько тестов на моей локальной базе данных, где у меня только 670 000 записей выборок, и INSTR () работает, но с точки зрения производительности это выглядит намного хуже. Мне придется подождать до завтра, чтобы провести этот тест на промышленном образце.
Вот анализ (объяснение) для моего исходного запроса:
Id select_type table type posible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE product_restrict range PRIMARY PRIMARY 201 17 2.00 76.47 100.00 Using where
А вот для ИНСТР:
Id select_type table type posible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE product_restrict ref PRIMARY PRIMARY 98 const 335022 671732.00 100.00 0.00 Using where
Запрос INSTR, например:
SELECT *
FROM product_restrict
WHERE
region='XXX' AND
INSTR('98765432109876543', id) = 1 AND (
now() >= from_dttm AND
( now() < to_dttm OR to_dttm is null)
);