2 где пункты медленнее, чем разделенные запросы - PullRequest
0 голосов
/ 27 февраля 2019

Я использую Google Cloud SQL (версия для микро-сервера), чтобы выполнить несколько тестов производительности.

Я хочу выполнить следующий запрос:

select count(*) from table where A = valueA and B like "%input_string%";
+----------+
| count(*) |
+----------+
|   512997 |
+----------+
1 row in set (9.64 sec)

Если я запускаюпо отдельности я получаю:

select count(*) from table where A = valueA;
+----------+
| count(*) |
+----------+
|   512998 |
+----------+
1 row in set (0.18 sec)

select count(*) from table where B like "%input_string%";
+----------+
| count(*) |
+----------+
|   512997 |
+----------+
1 row in set (1.43 sec)

Как такое различие в производительности возможно ???

И столбцы A и B имеют индексы, поскольку они используются для упорядочения таблиц в веб-приложении.

Спасибо!РЕДАКТИРОВАТЬ: схема таблицы

table | CREATE TABLE `table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `A` varchar(9) DEFAULT NULL,
  `B` varchar(50) DEFAULT NULL,
  `C` varchar(10) DEFAULT NULL,
  `D` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `A` (`A`),
  KEY `B` (`B`)
) ENGINE=InnoDB AUTO_INCREMENT=512999 DEFAULT CHARSET=utf8

Ответы [ 2 ]

0 голосов
/ 08 марта 2019

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

where A = valueA and B like "%input_string%"; просит INDEX(A, B).Примечание. Этот составной индекс не эквивалентен двум вашим отдельным индексам.

Если вы используете индекс FULLTEXT для B, то это будет проще:

SELECT COUNT(*) FROM t
    WHERE MATCH(B) AGAINST('+input_string' IN BOOLEAN MODE)
      AND A = valueA

(Использование подзапроса должно быть ненужным и медленным.)

0 голосов
/ 27 февраля 2019

В качестве опции можно использовать FULLTEXT INDEX и использовать MATCH().

CREATE TABLE `table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `A` varchar(9) DEFAULT NULL,
  `B` varchar(50) DEFAULT NULL,
  `C` varchar(10) DEFAULT NULL,
  `D` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY(A), 
  FULLTEXT INDEX(B)
) ENGINE=InnoDB AUTO_INCREMENT=512999 DEFAULT CHARSET=utf8

И переписать запрос

SELECT 
 count(*)
FROM 
`table`
WHERE
   A = 'A'
 AND 
   B IN (

     SELECT 
      B
     FROM 
      `table`
     WHERE
   MATCH(B) AGAINST('+input_string' IN BOOLEAN MODE)
)

Внутренний SQL отфильтрует возможный результат на основе индекса FULLTEXT.И внешний SQL будет выполнять другую фильтрацию.

Вы также можете использовать UNION ALL, теперь я думаю об этом.Надо по этому вопросу CREATE TABLE заявить.Общая идея состоит в том, чтобы получить два счета для обоих фильтров и выбрать наименьшее значение в качестве действительного.

Запрос

SELECT 
 MIN(counted) AS 'COUNT(*)' # Result 512997
FROM (

  select count(*) AS counted from `table` where A = 'A' # Result 512998
  UNION ALL
  select count(*)  from `table` where B like "%input_string%" # Result  512997
) AS counts
...