Может ли мой запрос с несколькими операторами LIKE и REGEXP быть более эффективным? - PullRequest
1 голос
/ 13 марта 2011

Я создаю динамический запрос для выбора удаленных доменных имен из моей базы данных.На данный момент есть десяток строк, но я собираюсь вскоре получить данные, в которых будет записано до 500 000 строк.

Схема - это всего лишь одна таблица, содержащая 4 столбца:

CREATE TABLE `DroppedDomains` (
  `domainID` int(11) NOT NULL AUTO_INCREMENT,
  `DomainName` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
  `DropDate` date DEFAULT NULL,
  `TLD` varchar(5) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`domainID`)
) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

Я не создал схему, это схема действующей базы данных.Вот примеры данных:

enter image description here

Я построил, вероятно, самый сложный тип запроса ниже.Критерии таковы:

ВЫБЕРИТЕ любое количество доменов, которые

  1. начинаются со слова «начинается»
  2. заканчиваются словом «заканчивается»
  3. Содержит слово 'containsThis' в любом месте имени домена
  4. Содержит слово 'ContainsThisToo' в любом месте имени домена
  5. Включает хотя бы одну цифру
  6. Доменное имя должно содержать не менее 49 символов.Мультибайты должны учитываться как один символ (я использовал CHAR_LENGTH).
  7. Имя домена должно быть не менее 65 символов.
  8. TLD должен быть 'org'
  9. DropDate должен быть позже, чем 2009-11-01

Вот мой запрос:

SELECT
*
FROM
DroppedDomains

WHERE

1=1

AND DomainName LIKE 'starts%ends'
AND DomainName LIKE '%containsThis%'
AND DomainName LIKE '%containsThisToo%'
AND DomainName LIKE '%-%'
AND DomainName REGEXP '[0-9]'
AND CHAR_LENGTH(DomainName) > 49
AND CHAR_LENGTH(DomainName) < 65
AND TLD = 'org'
AND DropDate > '2009-11-01'

Вот мои вопросы

  1. Будет ли это чрезвычайно полезным для производительности, учитывая, что у меня будет полмиллиона строк, если я сделаю столбец TLD своей собственной таблицей ипросто сделать столбец TLD внешним ключом к этому?Всего будет 5 ДВУ (com, net, org, info, biz).Я понимаю, что в реальном мире есть больше ДВУ, но у этого приложения будет только 5. Пользователь не может указать свой собственный ДВУ.

  2. Я знаю, что REGEXP и 500 000 строк, вероятно,рецепт катастрофы.Могу ли я в любом случае избежать REGEXP?

  3. Есть ли какие-либо другие оптимизации для запроса, который я могу сделать?Например, объединить LIKE с или использовать другие функции, например INSTR?И должен ли я реализовать какой-то конкретный механизм кэширования?

Ответы [ 2 ]

3 голосов
/ 13 марта 2011

Если у вас есть шаблон LIKE, который начинается с постоянного префикса, и у вас есть индекс для этого поля, тогда индекс можно использовать для очень быстрого поиска строк, начинающихся с префикса. К счастью, у вас есть именно такая ситуация:

AND DomainName LIKE 'starts%ends'

Если только несколько значений начинаются с starts, то эти строки будут найдены очень быстро, а остальные выражения будут проверены только для этих строк. Вы можете проверить, что индекс используется, запустив EXPLAIN SELECT ....

1 голос
/ 13 марта 2011

Вы должны запланировать создание индексов в соответствии с запросами, которые вы планируете использовать.

  • , если у вас будут запросы, которые фильтруют только по DropDate, тогда будет полезен индекс по DropDate..
  • если у вас будут запросы, сгруппированные по TLD, тогда будет полезен индекс по TLD.
  • , если у вас будут запросы, которые выполняют поиск только по длине DomainName, вы можетерассмотрите возможность добавления поля DomainNameLength, которое имеет именно это (и индекс для этого), чтобы длина не вычислялась при каждом выполнении запроса.
  • , если у вас будут запросы, которые выполняют поиск (фильтр) по двум полям (например, TLD и DropDate), тогда вам, вероятно, понадобится индекс из двух столбцов для этих полей.
  • и т. д.

Если ваш единственный запрос, который вы будете использовать, является сложнымВы упоминаете, что совет Марка (об индексе для DomainName) является лучшим.

Относительно вопроса 1 о TLD поле:

Если вы действительно собираетесь иметь только небольшое число (например,5) вариантов этого и вамне планируете использовать все доступные tlds, вы можете использовать ENUM type .

CREATE TABLE(
   ....
   tld ENUM('com', 'net', 'org', 'info', 'biz')
)
...