MySQL зависает при выполнении запроса. Как я могу сделать это более эффективным? - PullRequest
1 голос
/ 21 июня 2010

Мы пытаемся выполнить запрос, чтобы получить все неоплаченные счета. Когда я запускаю запрос, он вешает всю нашу систему. Мне просто интересно, есть ли способ сделать это более эффективным. SQL не моя сильная сторона.

$ query = "SELECT SQL_CALC_FOUND_ROWS i.order_id, o. , acct. , (SELECT SUM (items.item_qty) AS КОЛИЧЕСТВО ИЗ элементов WHERE items.order_id = o.order_id) AS order_qty
ИЗ элементов КАК я
ВНУТРЕННИЕ РЕКЛАМНЫЕ ЗАКАЗЫ КАК ВКЛЮЧЕНЫ o.order_id = i.order_id
ВНУТРЕННИЕ СОЕДИНЕНИЯ Транзакции включены t.order_id = o.order_id
ВНУТРЕННИЕ РЕГИСТРАЦИОННЫЕ СЧЕТА КАК ВКЛЮЧЕНО o.acct_id = acct.acct_id
ВНУТРЕННЕЕ ПРИСОЕДИНЕНИЕ ship_to AS st ON o.ship_id = st.ship_id
ГДЕ o.order_status = 7 И o.order_date> '2009-05-01 00: 00: 00'
И (ВЫБЕРИТЕ СУММУ (items.item_price) КАК ЦЕНУ ИЗ ИЗДЕЛИ ГДЕ items.order_id = o.order_id) * ( ВЫБЕРИТЕ СУММУ (items.item_qty) КАК КОЛИЧЕСТВО ИЗ элементов WHERE items.order_id = o.order_id) + o.order_ship_amount- (SELECT sum (trans_amount) ОТ транзакций WHERE t.order_id = o.order_id AND trans_pending = 0)! = 0
И acct.is_wholesale = 1
GROUP BY o.order_id
ЗАКАЗАТЬ o.order_date
LIMIT $ offset, $ limit ";

Вот информация о расположении таблицы для необходимых таблиц:

CREATE TABLE items (
item_id int (11) NOT NULL auto_increment,
order_id int (11) NOT NULL по умолчанию '0',
prod_id int (11) NOT NULL по умолчанию '0',
scat_id int (11) NOT NULL по умолчанию '0',
inv_id int (11) NOT NULL по умолчанию '0',
item_qty int (11) NOT NULL по умолчанию '0',
item_price float (10,3) NOT NULL по умолчанию '0.000',
item_mfg varchar (200) NOT NULL по умолчанию '0',
item_group int (11) NOT NULL по умолчанию '0',
item_ship_date datetime NOT NULL по умолчанию '0000-00-00 00:00:00',
date_created datetime NOT NULL по умолчанию '0000-00-00 00:00:00',
ПЕРВИЧНЫЙ КЛЮЧ (item_id),
КЛЮЧ prod_id (prod_id),
КЛЮЧ order_id (order_id),
КЛЮЧ inv_id (inv_id),
КЛЮЧ scat_id (scat_id)
) ДВИГАТЕЛЬ = MyISAM AUTO_INCREMENT = 834659 CHARSET ПО УМОЛЧАНИЮ = латинский 1

CREATE TABLE orders (
order_id int (11) NOT NULL auto_increment,
acct_id int (11) NOT NULL по умолчанию '0',
order_date отметка времени NOT NULL по умолчанию CURRENT_TIMESTAMP,
order_confirm_date datetime NOT NULL по умолчанию '0000-00-00 00:00:00',
order_approval_date datetime NOT NULL по умолчанию '0000-00-00 00:00:00',
order_deposit_date datetime NOT NULL по умолчанию '0000-00-00 00:00:00',
order_sent_to_mfg datetime NOT NULL по умолчанию '0000-00-00 00:00:00',
order_due_date datetime NOT NULL по умолчанию "0000-00-00 00:00:00",
order_ship_date дата и время не имеют значения по умолчанию "0000-00-00 00:00:00",
order_exp_ship_date дата и время не равно по умолчанию "0000- 00-00 00:00:00 ',
order_ship_type текст NOT NULL,
order_ship_amount float (10,2) NOT NULL по умолчанию' 0.00 ',
order_mfg_name int (11) NOT NULL по умолчанию '0',
order_notes текст NOT NULL,
order_status int (11) NOT NULL по умолчанию '0',
ship_id int (11) NOT NULL по умолчанию '0',
bill_id int (11) NOT NULL по умолчанию '0',
order_requested_quote int (11) NOT NULL по умолчанию '0',
order_submitted int (11) NOT NULL по умолчанию '0'
1102 * в t (11) NOT NULL по умолчанию '0',
order_po_no varchar (25) NOT NULL по умолчанию '',
qd_id int (11) NOT NULL по умолчанию '0',
order_inactive int (11) NOT NULL по умолчанию '0',
order_cancelled datetime NOT NULL по умолчанию '0000-00-00 00:00:00',
site_id int (11) NOT NULL по умолчанию '0' ,
ПЕРВИЧНЫЙ КЛЮЧ (order_id),
КЛЮЧ ship_id (ship_id),
КЛЮЧ bill_id (bill_id),
КЛЮЧ acct_id (acct_id) ,
KEY site_id (site_id)
) ENGINE = MyISAM AUTO_INCREMENT = 20311622 CHARSET ПО УМОЛЧАНИЮ = latin1

CREATE TABLE transactions (
trans_id int (11) NOT NULL auto_increment,
order_id int (11) NOT NULL по умолчанию '0',
trans_pnref текст NOT NULL,
trans_card_type text NOT NULL,
trans_date datetime NOT NULL default по умолчанию '0000-00-00 00:00:00',
trans_amount float (10,2) NOT NULL по умолчанию '0.00',
trans_type текст NOT NULL,
trans_tender текст NOT NULL,
trans_po_no текст NOT NULL,
trans_origin текст NOT NULL,
trans_rep int (11) NOTNULL по умолчанию '0',
trans_po_received datetime NOT NULL по умолчанию '0000-00-00 00:00:00',
trans_inactive int (11) NOT NULL по умолчанию '0',
trans_pending int (11) NOT NULL по умолчанию '0',
trans_secured int (11) NOT NULL по умолчанию '0',
site_id int (11) NOT NULL по умолчанию '0',
ПЕРВИЧНЫЙ КЛЮЧ (trans_id),
КЛЮЧ cod_id (order_id),
КЛЮЧ site_id (site_id)
) ДВИГАТЕЛЬ = MyISAM AUTO_INCREMENT = 211554 CHARSET ПО УМОЛЧАНИЮ = latin1

CREATE TABLE accounts (
acct_id int (11) NOT NULL auto_increment,
acct_signup отметка времени NOT NULL по умолчанию CURRENT_TIMESTAMP,
acct_first текст NOT NULL,
acct_last текстNOT NULL,
acct_company текст NOT NULL,
acct_email текст NOT NULL,
acct_email_cc текст NOT NULL,
acct_email_bcc текст NOT NULL,
acct_phone текстNOT NULL,
acct_fax текст NOT NULL,
acct_password текст NOT NULL,
acct_default_ship int (11) NOT NULL по умолчанию '0',
acct_default_bill int (11)NOT NULL по умолчанию '0',
is_account int (1) NOT NULL по умолчанию '0',
is_wholesale int (1) NOT NULL по умолчанию '0',
site_id int (11)) NOT NULL по умолчанию '0',
tpsg_id int (11) NOT NULL по умолчанию '0',
ПЕРВИЧНЫЙ КЛЮЧ (acct_id),
КЛЮЧ acct_default_ship (acct_default_ship),
KEY acct_default_bill (acct_default_bill),
KEY site_id (site_id),
KEY tpsg_id (tpsg_id)
) ENGINE = MyISAM AUTO_INCREMENT = 264476 CHARSET ПО УМОЛЧАНИЮ =latin1

CREATE TABLE ship_to (
ship_id int (11) NOT NULL auto_increment,
acct_id int (11) NOT NULL по умолчанию '0',
ship_firstтекст NOT NULL,
ship_last текст NOT NULL,
ship_company текст NOT NULL,
ship_address1 текст NOT NULL,
ship_address2 текст NOT NULL,
ship_cityтекст NOT NULL,
ship_state текст NOT NULL,
ship_zip текстNOT NULL,
ship_country текст NOT NULL,
ship_phone текст NOT NULL,
ship_fax текст NOT NULL,
ship_notes текст NOT NULL,
ship_inactive int(1) без знака NOT NULL по умолчанию '0',
ПЕРВИЧНЫЙ КЛЮЧ (ship_id),
КЛЮЧ acct_id (acct_id)
) ENGINE = MyISAM AUTO_INCREMENT = 241339 CHARSET ПО УМОЛЧАНИЮ = latin1

Я хочу, чтобы этот запрос выполнял получение информации о заказе для всех заказов со статусом 7 после 1 мая 2009 г. и суммировал цены для всех позиций в заказе, умноженные на количество, а затем добавлялсумму отгрузки и вычтите из нее уплаченную сумму и убедитесь, что она не равна 0. Также счет должен быть оптовым.

Я знаю, что этот запрос очень неэффективен, но я не уверен, как еще это сделать.Наша система настолько перегружена, что в целом она очень запаздывает.

Буду признателен за любую помощь!

Ответы [ 5 ]

1 голос
/ 21 июня 2010

Используйте объяснение для анализа плана выполнения запроса: http://dev.mysql.com/doc/refman/5.1/en/using-explain.html и http://dev.mysql.com/doc/refman/5.1/en/explain.html

Обычно подзапросы в WHERE очень медленные, попробуйте переписать их как JOIN.

0 голосов
/ 22 июня 2010
SELECT   
    o.order_id,  
    o.order_ship_amount,  
    SUM(i.item_qty * i.item_price) AS item_amount,  
    (   SELECT SUM(trans_amount) FROM transactions
        WHERE order_id = o.order_id AND trans_pending = 0
    ) AS trans_amount,
    ... etc.
FROM  
    orders AS o  
INNER JOIN accounts AS acct ON o.acct_id = acct.acct_id  
INNER JOIN ship_to AS st ON o.ship_id = st.ship_id  
INNER JOIN items AS i ON o.order_id = i.order_id  
WHERE   
    o.order_status = 7   
    AND o.order_date > '2009-05-01 00:00:00'  
    AND acct.is_wholesale = 1   
GROUP BY o.order_id  
HAVING item_amount + order_ship_amount - trans_amount != 0  
ORDER BY o.order_date  
0 голосов
/ 21 июня 2010

Посмотрите, описывает ли это ваш запрос немного проще (и не более эффективный.)

SELECT   
    o.order_id,  
    o.order_ship_amount,  
    SUM(i.item_qty * i.item_price) AS item_amount,  
    SUM(trans_amount) AS trans_amount,  
    ... etc.
FROM  
    orders AS o  
INNER JOIN accounts AS acct ON o.acct_id = acct.acct_id  
INNER JOIN ship_to AS st ON o.ship_id = st.ship_id  
INNER JOIN items AS i ON o.order_id = i.order_id  
LEFT JOIN transactions AS t ON t.order_id = o.order_id  
    AND trans_pending = 0  
WHERE   
    o.order_status = 7   
    AND o.order_date > '2009-05-01 00:00:00'  
    AND acct.is_wholesale = 1   
GROUP BY o.order_id  
HAVING item_amount + order_ship_amount - trans_amount != 0  
ORDER BY o.order_date  

Убедитесь, что вы можете прочитать и понять это - я не проверял.

0 голосов
/ 21 июня 2010

Поскольку вы уже присоединяетесь к элементам и транзакциям по order_id, Я думаю, что вы можете отказаться от своего состояния подзапроса и переместить проверки в HAVING.

Попробуйте выполнить этот запрос:

SELECT SQL_CALC_FOUND_ROWS i.order_id, o.*, acct.*, SUM(items.item_qty) AS order_qty
FROM items AS i
INNER JOIN orders AS o ON o.order_id = i.order_id
INNER JOIN transactions AS t ON t.order_id = o.order_id
INNER JOIN accounts AS acct ON o.acct_id = acct.acct_id
INNER JOIN ship_to AS st ON o.ship_id = st.ship_id
WHERE o.order_status=7 AND o.order_date > '2009-05-01 00:00:00'
AND acct.is_wholesale=1
GROUP BY o.order_id
HAVING ( SUM(items.item_price) * SUM(items.item_qty) + o.order_ship_amount - SUM(transactions.trans_amount) ) != 0
ORDER BY o.order_date
LIMIT $offset, $limit
0 голосов
/ 21 июня 2010

Это подзапросы в предложении WHERE. Нактибала ударить ногтем по голове там ...

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

...