запрос замедляется, если добавить поле к условию where

0

У меня есть таблица Mysql со скриптами около 500 тыс. Записей.

CREATE TABLE IF NOT EXISTS 'p_transactions' (
  'transaction_id' bigint(10) unsigned NOT NULL,
  'amount' decimal(19,2) NOT NULL,
  'dt' bigint(1) NOT NULL,
  'transaction_status' int(1) NOT NULL,
  'transaction_type' varchar(15) NOT NULL,
  'payment_method' varchar(25) NOT NULL,
  'notes' text NOT NULL,
  'member_id' int(10) unsigned NOT NULL,
  'new_amount' decimal(19,2) NOT NULL,
  'paid_amount' decimal(19,2) NOT NULL,
  'secret_code' char(40) NOT NULL,
  'internal_status' varchar(40) NOT NULL,
  'ip_addr' varchar(15) NOT NULL,
  'description' text NOT NULL,
  'seller_transaction_id' varchar(50) DEFAULT NULL,
  'return_url' varchar(255) DEFAULT NULL,
  'fail_url' varchar(255) DEFAULT NULL,
  'success_url' varchar(255) DEFAULT NULL,
  'result_url' varchar(255) DEFAULT NULL,
  'user_fee' decimal(19,3) DEFAULT '0.000',
  'currency' char(255) DEFAULT 'USD',
  'gateway_transaction_id' char(255) DEFAULT NULL,
  'load_amount' decimal(19,2) NOT NULL,
  'transaction_mode' varchar(1) NOT NULL DEFAULT '',
  'p_fee' decimal(19,2) NOT NULL,
  'country' varchar(2) NOT NULL,
  'email' varchar(255) NOT NULL,
  'vat' decimal(19,2) NOT NULL DEFAULT '0.00',
  'name' varchar(255) NOT NULL,
  'bdate' varchar(255) NOT NULL,
  'child_method' varchar(255) NOT NULL,
  'processing_fee' decimal(19,2) NOT NULL DEFAULT '0.00',
  'flat_fee' varchar(1) NOT NULL DEFAULT 'n',
  'user_fee_sum' decimal(19,2) NOT NULL DEFAULT '0.00',
  'p_fee_sum' decimal(19,2) NOT NULL DEFAULT '0.00',
  'dt_open' bigint(1) NOT NULL DEFAULT '0',
  'user_fee_type' varchar(1) NOT NULL DEFAULT 'r',
  'custom_gateway_fee' decimal(19,2) NOT NULL DEFAULT '0.00',
  'paid_currency' varchar(3) NOT NULL DEFAULT 'USD',
  'paid_microtime' bigint(10) unsigned NOT NULL,
  'check_ballance' varchar(1) NOT NULL DEFAULT 'n',
  PRIMARY KEY ('transaction_id'),
  KEY 'member_id' ('member_id'),
  KEY 'payment_method' ('payment_method'),
  KEY 'child_method' ('child_method'),
  KEY 'check_ballance' ('check_ballance'),
  KEY 'dt' ('dt'),
  KEY 'transaction_type' ('transaction_type'),
  KEY 'paid_microtime' ('paid_microtime')
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Когда я выполняю запрос

SELECT *
FROM 'p_transactions'
WHERE dt >= 1517443200
AND dt <= 1523404799
AND member_id =  2051
ORDER BY 'paid_microtime' DESC
 LIMIT 50;

он работает 0,000 сек. (+ 0,016 с)

но если я добавлю к запросу это условие AND transaction_status = 7

SELECT *
FROM 'p_transactions'


WHERE dt >= 1517443200
AND dt <= 1523404799
AND member_id =  2051
AND transaction_status =  7

ORDER BY 'paid_microtime' DESC
 LIMIT 50

выполнение запроса 12,938 сек. (+ 0,062 с)

Пожалуйста, помогите мне выяснить причину такого поведения

PS. Был указатель на transaction_status и он увеличил время выполнения еще больше.

  • 0
    Нам нужно увидеть схему и какие индексы определены. SHOW CREATE TABLE дает точно правильный вывод. При необходимости вы можете отредактировать что-либо показательное и удалить все столбцы, не относящиеся к вашей проблеме. Эта внешняя ссылка может устареть или измениться, поэтому вы должны держать свой вопрос в отдельности.
Теги:
query-optimization

2 ответа

1
Лучший ответ

Добавьте подходящий индекс, например:

ON payzoff_transactions (member_id, dt) 

или же

ON payzoff_transactions (member_id, dt, transaction_status)

Мы хотим, member_id столбец member_id был ведущим столбцом в индексе, из-за сравнения равенства, и мы ожидаем, что результат будет существенно меньшим подмножеством всей таблицы. После этого мы хотим dt столбца из-за "сканирования диапазона".

Включение дополнительных столбцов в индекс может позволить MySQL проверить это условие, используя значения из индекса, без посещения/поиска строки на основных страницах таблицы.

Любой из этих индексов подходит для обоих запросов, указанных в вопросе.


Используйте EXPLAIN чтобы увидеть план выполнения... какой индекс используется.

Там действительно не обойти операцию "Использование файловой системы", так как мы тянем небольшое подмножество всей таблицы.

(Если бы мы вытащили всю таблицу (или огромное подмножество), мы могли бы избежать дорогостоящей операции сортировки с планом доступа, который вытягивает строки в обратном порядке индекса, причем у него есть индекс с ведущим столбцом paid_microtime.)

  • 0
    ты видел скрипку? Есть индексы, которые вы упомянули. Объясните, говорит возможные ключи member_id, dt, которые уже были добавлены
  • 0
    @OleksandrKhavdiy: Я не вижу каких - либо составных индексов в определении таблицы. Я видел только индексы на одноэлементных столбцах. (И индексы для отдельных столбцов не эквивалентны составному индексу.) Оба составных индекса, которые я рекомендую, сделали бы индекс только для столбца member_id избыточным.
0

Для исходного запроса эти

INDEX(member_id, dt)
INDEX(member_id, paid_microtime)

Для вторичного запроса

INDEX(transaction_status, member_id, dt)
INDEX(transaction_status, member_id, paid_microtime)

Не вдаваясь в детали распределения значений данных, мы не можем объяснить, почему один запрос намного медленнее; однако мои 4 индекса должны заставить оба запроса работать быстрее в большинстве случаев.

Больше обсуждений о том, как я придумал эти индексы (и почему (member_id, dt, transaction_status) не так хорош): http://mysql.rjweb.org/doc.php/index_cookbook_mysql

Ещё вопросы

Сообщество Overcoder
Наверх
Меню