Оператор SQL Between слишком медленный - PullRequest
0 голосов
/ 02 ноября 2019

Спасибо за вашу помощь, у нас есть SQL-запрос, который выполнялся в течение 5 лет, и он был в порядке. С приходом новой загрузки запросу потребовалось более 4 часов, и время ожидания истекло, поэтому мы выделили проблему для следующего оператора:

Этот оператор SQL был упрощен для легкого чтения:

select * from table1 t1, table2 t2
where (t1.ProductCode between t2.BeginNumber and t2.EndNumber)

Example with values
select * from table1 t1, table2 t2
where ('12345' between '12345' and '12345')

ProductCode, BeginNumber, EndNumber имеет индекс BTree, и они имеют тип varchar.

Table1 имеет 50000 строк. Table2 имеет 113000 строк

BeginNumber и EndNumber на самом деле являются одним и тем же числом, диапазон отсутствуетв них (например, BeginNumber = 12345 EndNumber = 12345), но для обеспечения соответствия мы не можем изменить предложение «Между» на «Равное», поскольку в будущем они могут изменить число на диапазон.

Это работает на MYSQL 5.6.11, настроенной памяти InnoDB 4 ГБ, Intel i7-8550, 8 ГБ ОЗУ. Она была разработана как небольшая некритическая база данных, но недавние изменения в источнике входящих данных значительно выросли, и количество рабочих мествисят, и он слишком долго зависает в этом утверждении (4 часа).

Аппаратное обеспечение будет обновлено до 16 ГБ ОЗУ, SSD, кроме этого, как мы можем заставить оператор работать быстрее?

Ответы [ 3 ]

1 голос
/ 02 ноября 2019

Вам нужно проверить планы объяснения, чтобы увидеть, что происходит.

Во-первых, типы точно одинаковы. Это очень важно. Сличение имеет значение, если это строки. ,,Ваш индивидуальный запрос предполагает, что они являются строками. Ваше имя предлагает иное.

Во-вторых, для этого запроса:

select *
from table1 t1 join
     table2 t2
     on t1.ProductCode between t2.BeginNumber and t2.EndNumber

Единственный подходящий индекс находится на t1(productcode). MySQL может столкнуться с проблемами при использовании. Так что, возможно, было бы лучше сформулировать запрос следующим образом:

select *
from table2 t2 join
     table1 t1
     on t2.BeginNumber <= t1.ProductCode and
        t2.EndNumber >= t1.ProductCode;

Это дает понять, что table2 будет «ведущей» таблицей в объединении. То есть MySQL будет сканировать table2 и затем искать соответствующие совпадающие строки в t1.

. Примечание. Ваш пример со значениями не имеет ничего общего с вашим первым запросом. Этот пример обрабатывает предложение where на этапе компиляции и отмечает, что оно всегда верно. Затем он продолжает делать cross join. Он вернет все возможные пары из двух таблиц. Вы, вероятно, видите, что он работает быстро, потому что вы смотрите на возвращаемую первую строку , а не на ожидание всех возможных комбинаций.

0 голосов
/ 02 ноября 2019

Иногда это помогает изменить МЕЖДУ на 2 критерия.

И при изменении запроса можно также идти в ногу со временем и использовать современный синтаксис JOIN.

SELECT * 
FROM table1 t1
JOIN table2 t2 
  ON (t2.BeginNumber <= t1.ProductCode AND t2.EndNumber >= t1.ProductCode)

И, вероятно, не мешало бы сделать ТАБЛИЦУ АНАЛИЗА для обеих таблиц.

0 голосов
/ 02 ноября 2019

Вы должны проверить правильность индекса

select * 
from table1 t1
INNER  table2 t2 ON t1.ProductCode  between  t2.BeginNumber and t2.EndNumber

Убедитесь, что у вас есть правильный индекс

table1 column  ProductCode 

и таблица

table2 composite index  on columns  (BeginNumber, EndNumber)
...