Убыстрение многострадального LIKE('%ABC%')

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

Ответить
Serg-avens
Сообщения: 5
Зарегистрирован: 29 июл 2005, 13:26

Убыстрение многострадального LIKE('%ABC%')

Сообщение Serg-avens » 24 ноя 2007, 03:03

Поиск курил. Но, всё же.
Есть справочник товаров всего в 30 тыс. записей.
В нём есть поле артикула NAME_TOVAR Varchar(100). По нему создан уникальный индекс.
Поиск нужного товара идёт через Select NAME_TOVAR ..... WHERE NAME_TOVAR LIKE('%ABC%') выполняется где-то за 0.4-0.5 с.

А хочется ещё быстрее :)
Хочется потому, что юзеры приложения знают, что если перебирать не все 30 тыс. записей, а только небольшую часть из них (поиск товаров какой-то одной группы), то поиск идёт всего за 0.1 с.

belov-evgenii
Сообщения: 52
Зарегистрирован: 28 сен 2007, 10:19

Сообщение belov-evgenii » 24 ноя 2007, 10:53

может starting with?

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Re: Убыстрение многострадального LIKE('%ABC%')

Сообщение WildSery » 24 ноя 2007, 12:13

Serg-avens писал(а):LIKE('%ABC%')
По такому запросу никакой индекс не может использоваться даже теоретически.

Serg-avens
Сообщения: 5
Зарегистрирован: 29 июл 2005, 13:26

Сообщение Serg-avens » 24 ноя 2007, 12:21

Еснно, Starting with работает в 2 раза быстрее, не 0.5с, а 0.2 с.
Аналогичный результат получается, если в LIKE убрать начальный знак %.
Но, юзеры не согласятся. Уже привыкли, что можно набирать не первые буквы артикула, а любые из середины.

Serg-avens
Сообщения: 5
Зарегистрирован: 29 июл 2005, 13:26

Re: Убыстрение многострадального LIKE('%ABC%')

Сообщение Serg-avens » 24 ноя 2007, 13:02

WildSery писал(а): По такому запросу никакой индекс не может использоваться даже теоретически.
Вобщем, остаётся только не допускать распухания справочника товаров. В любом случае, она будет перебираться перебором?
Хотя странно, IBExpert показывает, что план запроса использует имеющийся индекс по артикулу.
Кстати, его статистика 0,000036
Это нормально или как?
Спасибо заранее

belov-evgenii
Сообщения: 52
Зарегистрирован: 28 сен 2007, 10:19

Сообщение belov-evgenii » 24 ноя 2007, 15:20

Покажи запрос и план. Никто тебе на поверит, что like %abc% использует индекс

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Re: Убыстрение многострадального LIKE('%ABC%')

Сообщение WildSery » 24 ноя 2007, 16:15

Serg-avens писал(а):В любом случае, она будет перебираться перебором?
Да.
Для поиска в строках или тексте делаются индексированные словари, содержащие слова и/или словосочетания, и ссылки из самой строки на содержащиеся в ней лексемы. Соответсвенно, "ускоренно" искать можно только в тексте, уже проиндексированным таким механизмом. Это весьма трудоёмкая и нетривиальная задача.

stix-s
Заслуженный разработчик
Сообщения: 557
Зарегистрирован: 13 дек 2005, 11:52

Re: Убыстрение многострадального LIKE('%ABC%')

Сообщение stix-s » 26 ноя 2007, 07:23

Serg-avens писал(а): Вобщем, остаётся только не допускать распухания справочника товаров.
Возможно стоит разбить товары на категории, тогда перебор будет не по 30000, а скажем по 5000

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Re: Убыстрение многострадального LIKE('%ABC%')

Сообщение Dimitry Sibiryakov » 26 ноя 2007, 08:39

WildSery писал(а):Это весьма трудоёмкая и нетривиальная задача.
Да ну что там трудоемкого для такого простого случая?.. В триггерах строка рубится на куски с помощью SUBSTRING(... FROM 2) и складывается в индексную таблицу.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Re: Убыстрение многострадального LIKE('%ABC%')

Сообщение WildSery » 26 ноя 2007, 10:23

Dimitry Sibiryakov писал(а):рубится на куски с помощью SUBSTRING(... FROM 2)
А? Мысль не догнал :(

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 26 ноя 2007, 13:07

Ну, примерно такого плана триггер:

Код: Выделить всё

s=new.name;
while (s is not null) do
begin
 insert ind_table values (s);
 s=substring(s from 2);
end;

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 26 ноя 2007, 19:11

Dimitry Sibiryakov писал(а):Ну, примерно такого плана триггер:
А. Ясно.
Хотя, решение нишевое, мягко говоря.

Ответить