Простой SQL-запрос длится вечно - PullRequest
0 голосов
/ 20 сентября 2018

Я использую mysql-workbench и mysql сервер на ubunt 18 машине с 16 ГБ ОЗУ.

У меня есть схема с именем ips и две таблицы, скажем: table1 и table2table1 и table2 есть два поля: ip и description, биты имеют тип string.У меня много записей.table1 имеет 779938 записей, а table2 имеет 136657 записей.

Мне нужно сделать совместный запрос, чтобы найти число ip s в table2, которое имеет description, начинается с str1% и не содержит str2 и не содержит str3.В то же время эти ip s имеют описание в table1, которое не начинается с str1% и содержит либо str2, либо str3.

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

SELECT COUNT(`table2`.`ip`)
FROM `ips`.`table2`, `ips`.`table1`
WHERE `table2`.`ip` = `table1`.`ip`
       AND (LOWER(`table1`.`description`) NOT LIKE 'str1%' 
             AND (LOWER(`tabl1`.`description`) LIKE '%-str2-%' 
                   OR LOWER(`table1`.`description`) LIKE '%-str3-%'
                 )
            )
       AND (LOWER(`table2`.`description`) LIKE 'str1%'
            AND LOWER(`table2`.`description`) NOT LIKE '%-str2-%' 
            AND LOWER(`table2`.`description`) NOT LIKE '%-str3-%'
           );

Однако запрос никогда не заканчивается.Продолжительность ?, и я никогда не получаю результат.Можете ли вы помочь?

РЕДАКТИРОВАТЬ:

Вот ШОУ СОЗДАТЬ ШОУ и

1) SHOW CREATE TABLE ips . table2 ;

CREATE TABLE `table2` (
  `ip` varchar(500) DEFAULT NULL,
  `description` varchar(500) DEFAULT NULL,
  `type` varchar(500) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1

2) SHOW CREATE TABLE ips . table1 ;

CREATE TABLE `table1` (
  `ip` varchar(500) DEFAULT NULL,
  `description` varchar(500) DEFAULT NULL,
  `type` varchar(500) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1

3) EXPLAIN <query>

# id, select_type, table, partitions, type, possible_keys, key, key_len, ref, rows, filtered, Extra
1, SIMPLE, table2, , ALL, , , , , 136109, 100.00, Using where
1, SIMPLE, table1, , ALL, , , , , 786072, 10.00, Using where; Using join buffer (Block Nested Loop)

РЕДАКТ. 2:

Данные для поля ip являются строками в этом формате: str.str.str.str Поле decription имеет следующий формат: str1-str2-str3-str4

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

Предыдущий ответ относительно индексации может оптимизировать запрос.Это может быть правильно.Но мне жаль, что я должен проверить ответ, который использовал для решения проблемы.Спасибо @Raymond Nijland за то, что он первым указал на проблему с индексированием, которая напомнила мне о первичных ключах.

Источник проблемы состоит в том, что обе таблицы в запросе не имели первичного ключа.Первичный ключ должен быть для ключа, который является уникальным и не нулевым.В моем случае у меня уже есть поле ip, готовое к серверу в качестве первичного ключа.Поскольку я использую mysql- workbench, я щелкаю правой кнопкой мыши по таблицам, нажимаю Alter Table, затем проверяю первичный ключ для соответствующего поля следующим образом:

enter image description here

Торешил мою проблему.

0 голосов
/ 20 сентября 2018

Вы получаете оператор ALL в плане выполнения, поскольку планировщик SQL не использует какой-либо индекс.Он выполняет полное сканирование таблицы для обеих таблиц.

Полное сканирование таблицы может быть оптимальным, если вы выбираете более 5% строк.В вашем случае это было бы хорошо, если бы ваш строковый префикс "str1" имел одну букву.Если в нем более одного символа, использование индекса может значительно повысить производительность.

Теперь сравнение, которое вы выполняете, не простое.Вы сравниваете не значение столбца, а результат выражения: LOWER(table1.description).Поэтому вам нужно создавать виртуальные столбцы и индексировать их, если вы хотите, чтобы этот запрос был быстрым.Это доступно в MySQL 5.7 и новее:

alter table table1 add lower_desc varchar(50) 
  generated always as (LOWER(description)) virtual;
create index ix1 on table1 (lower_desc);

alter table table2 add lower_desc varchar(50) 
  generated always as (LOWER(description)) virtual;
create index ix2 on table2 (lower_desc);

Эти индексы ускорят ваши запросы, когда префикс содержит два или более символов.Получите план выполнения снова.Теперь операторы ALL больше не должны быть там (операторы INDEX должны появиться на их месте).

Кстати, я думаю, что вы пропустили соединение в запросе.Я думаю, что это должно выглядеть так (я добавил третью строку):

SELECT COUNT(`table2`.`ip`)
FROM `ips`.`table2`
JOIN `ips`.`table1` on `ips`.`table1`.ip = `ips`.`table2`.ip
WHERE `table2`.`ip` = `table1`.`ip`
       AND (LOWER(`table1`.`description`) NOT LIKE 'str1%' 
             AND (LOWER(`tabl1`.`description`) LIKE '%-str2-%' 
                   OR LOWER(`table1`.`description`) LIKE '%-str3-%'
                 )
            )
       AND (LOWER(`table2`.`description`) LIKE 'str1%'
            AND LOWER(`table2`.`description`) NOT LIKE '%-str2-%' 
            AND LOWER(`table2`.`description`) NOT LIKE '%-str3-%'
           );

Кроме того, для оптимизации производительности соединения вам понадобится один (или оба) из индексов, показанных ниже:

create index ix3 on table1 (ip);
create index ix4 on table2 (ip);
...