Как улучшить производительность с помощью предложения ORDER BY - PullRequest
0 голосов
/ 12 ноября 2018

У меня есть запрос, который читает приблизительно 2,4 м строк данных.

Сам запрос выполняется нормально, но предложение ORDER BY вызывает проблемы с производительностью.Если я удаляю ORDER BY, выполнение запроса занимает 0,03 секунды.С ORDER BY это может занять от 4,5 до 5 секунд.

Есть ли еще способ оптимизировать этот запрос?Индексы были добавлены, так что это не решение.

РЕДАКТИРОВАТЬ 1 - Этот запрос является сокращенной версией гораздо большего запроса PDO, поэтому я считаю, что объединение необходимо.Вы можете увидеть основной запрос внизу этого поста.

SELECT t.processing_time, t.paymentType, t.status, t.merchantTransactionId, t.paymentBrand, t.amount, t.currency, t.code, t.holder, t.bin, t.last4Digits, t.recurringType, m.name AS merchant, c.name AS channel, concat(UPPER(SUBSTRING(trim(sp.status_description),1,1)), lower(SUBSTRING(trim(sp.status_description),2))) as status_description
FROM transactionsV2 t
JOIN channels c
ON t.entityId = c.uuid
JOIN merchants m
ON m.uuid = c.sender
JOIN status_payments sp 
ON t.code = sp.status_code
JOIN (
    SELECT t.id, t.processing_time FROM transactionsV2 t
    JOIN channels c ON t.entityId = c.uuid
    JOIN merchants m ON m.uuid = c.sender
    WHERE (t.processing_time >= "2018-11-08 00:00:00")
    AND (t.processing_time <= "2018-11-12 23:59:59")
    ORDER BY t.processing_time DESC
    LIMIT 1000
) t2
ON t.id = t2.id
WHERE t.status = 1

$transactions = DB::connection('mysql2')->select(DB::raw("SELECT t.processing_time, t.paymentType, t.status, t.merchantTransactionId, t.paymentBrand, t.amount, t.currency, t.code, t.holder, t.bin, t.last4Digits, t.recurringType, m.name AS merchant, c.name AS channel, concat(UPPER(SUBSTRING(trim(sp.status_description),1,1)), lower(SUBSTRING(trim(sp.status_description),2))) as status_description
FROM transactionsV2 t
JOIN channels c
ON t.entityId = c.uuid
JOIN merchants m
ON m.uuid = c.sender
JOIN status_payments sp 
ON t.code = sp.status_code
JOIN (
    SELECT t.id, t.processing_time FROM transactionsV2 t
    JOIN channels c ON t.entityId = c.uuid
    JOIN merchants m ON m.uuid = c.sender
    WHERE (t.processing_time >= :insTs1)
    AND (t.processing_time <= :insTs2)
    AND (:merchant1 IS NULL OR m.name LIKE :merchant2)
    AND (:channel1 IS NULL OR c.name LIKE :channel2)
    ORDER BY t.processing_time DESC
    LIMIT 1000
) t2
ON t.id = t2.id
WHERE (:status1 IS NULL OR t.status = :status2)
AND (:holder1 IS NULL OR holder LIKE :holder2)
AND (:paymentType1 IS NULL OR t.paymentType IN (".$paymentType."))
AND (:merchantTransactionId1 IS NULL OR merchantTransactionId LIKE :merchantTransactionId2)
AND (:paymentBrand1 IS NULL OR paymentBrand LIKE :paymentBrand2)
AND (:amount1 IS NULL OR amount = :amount2)
AND (:recurringType1 IS NULL OR t.recurringType = :recurringType2)"),
['status1' => $search->searchCriteria['status'],
'status2' => $search->searchCriteria['status'],
'holder1' => $search->searchCriteria['holder'],
'holder2' => '%'.$search->searchCriteria['holder'].'%',
'paymentType1' => $paymentType,
'merchantTransactionId1' => $search->searchCriteria['merchantTransactionId'],
'merchantTransactionId2' => '%'.$search->searchCriteria['merchantTransactionId'].'%',
'paymentBrand1' => $search->searchCriteria['paymentBrand'],
'paymentBrand2' => '%'.$search->searchCriteria['paymentBrand'].'%',
'amount1' => $search->searchCriteria['amount'],
'amount2' => $search->searchCriteria['amount'],
'recurringType1' => $search->searchCriteria['recurringType'],
'recurringType2' => $search->searchCriteria['recurringType'],
'merchant1' => $search->searchCriteria['merchant'],
'merchant2' => '%'.$search->searchCriteria['merchant'].'%',
'channel1' => $search->searchCriteria['channel'],
'channel2' => '%'.$search->searchCriteria['channel'].'%',
'insTs1' => $search->searchCriteria['fromDate'] . ' 00:00:00',
'insTs2' => $search->searchCriteria['toDate'] . ' 23:59:59']);

Ответы [ 2 ]

0 голосов
/ 12 ноября 2018

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

SELECT t.processing_time, 
       t.paymentType, 
       t.status, 
       t.merchantTransactionId, 
       t.paymentBrand, 
       t.amount, 
       t.currency, 
       t.code, 
       t.holder, 
       t.bin, 
       t.last4Digits, 
       t.recurringType, 
       m.name AS merchant, 
       c.name AS channel, 
       concat(UPPER(SUBSTRING(trim(sp.status_description),1,1)), 
       lower(SUBSTRING(trim(sp.status_description),2))) as status_description,
       row_number() over ()
FROM transactionsV2 t
JOIN channels c ON t.entityId = c.uuid
JOIN merchants m ON m.uuid = c.sender
WHERE (t.processing_time >= "2018-11-08 00:00:00") AND (t.processing_time <= "2018-11-12 23:59:59") and t.status = 1
ORDER BY t.processing_time DESC
LIMIT 1000  
0 голосов
/ 12 ноября 2018

Возможно, я что-то упускаю, но не вижу, чтобы подзапрос требовал join с. Этого достаточно?

SELECT t.id, t.processing_time
FROM transactionsV2 t
WHERE t.processing_time >= '2018-11-08' AND
      t.processing_time <= '2018-11-13'
ORDER BY t.processing_time DESC
LIMIT 1000

Если это так, поможет индекс на transactionsV2(processing_time) (при условии, что это не представление).

...