Дон Карлос (kastaneda) wrote,
Баг-репорт: долго грузится одна из страниц сайта.

К багрепорту приложен SQL-запрос, который долго выполняется (12 секунд на тестовом сервере). Вот такой вот запрос:

SELECT txt.taAttrValue AS `name`,
        mrins.Currency AS currency,
        mCode AS exchange,
        tsLastPrice AS price,
        tsNetCh AS `change`,
        tsNetChPercent AS `change-pers`,
        subgrp.taAttrValue AS subgroup,
        ord.taAttrValue AS instrOrder,
        trsess.MarketId AS marketId,
        trsess.tsTicker AS ticker
 FROM sfcTradeSession AS trsess
      JOIN sfcMarketInstrument AS mrins ON mrins.MarketId = trsess.MarketId AND
       mrins.miTicker = trsess.tsTicker
      JOIN sfcMarket AS mrkt ON mrins.MarketId = mrkt.mId
      JOIN sfcTradeInstrument AS trins ON mrins.InstrumentId = trins.tiId
      JOIN sfcTradeInstrumentAttribute AS txt ON trins.tiId = txt.InstrumentId
       AND txt.taAttrName = "name"
      JOIN sfcTradeInstrumentAttribute AS cntrgrp ON trins.tiId =
       cntrgrp.InstrumentId AND cntrgrp.taAttrName = "countryGroup"
      JOIN sfcTradeInstrumentAttribute AS instgrp ON trins.tiId =
       instgrp.InstrumentId AND instgrp.taAttrName = "group"
      LEFT JOIN sfcTradeInstrumentAttribute AS subgrp ON trins.tiId =
       subgrp.InstrumentId AND subgrp.taAttrName = "subgroup"
      LEFT JOIN sfcTradeInstrumentAttribute AS ord ON trins.tiId =
       ord.InstrumentId AND ord.taAttrName = "order"
 WHERE trsess.tsDate =
       (
        SELECT tsDate AS tsDate
        FROM sfcTradeSession AS intsess
        WHERE intsess.tsTicker = trsess.tsTicker
        ORDER BY tsDate DESC
        LIMIT 1
       ) AND
       trins.tiType = "commodity" AND
       cntrgrp.taAttrValue LIKE "Ukraine" AND
       instgrp.taAttrValue = "energy prices" AND
       subgrp.taAttrValue = "oil/gas"
 ORDER BY cast(instrOrder as signed) ASC;

Пиздец, правда?

Но я же профессионал. Я могу работать с любым говнокодом, если потребуется. Начинаю разбираться и нахожу, что источник тормозов — вложенный SELECT во WHERE, который выполняется по разу на каждую потенциальную строку результатов (а всего в таблице sfcTradeSession, по которой идёт выборка и которая используется в этом же SELECTе, порядка 100К строк и со временем будет на два порядка больше).

Решение получается быстро. Делаем VIEW с результатами, заменяющими тот вложенный SELECT:

CREATE VIEW vwTradeSessionEnd AS
  SELECT MAX(tsDate) AS tsDate, tsTicker
    FROM sfcTradeSession
    GROUP BY tsTicker;

...и используем его:

--- bug492	2009-05-14 13:46:29.000000000 +0300
+++ fix492	2009-05-14 16:48:23.000000000 +0300
@@ -23,17 +23,18 @@
        subgrp.InstrumentId AND subgrp.taAttrName = "subgroup"
       LEFT JOIN sfcTradeInstrumentAttribute AS ord ON trins.tiId =
        ord.InstrumentId AND ord.taAttrName = "order"
- WHERE trsess.tsDate =
-       (
-        SELECT tsDate AS tsDate
-        FROM sfcTradeSession AS intsess
-        WHERE intsess.tsTicker = trsess.tsTicker
-        ORDER BY tsDate DESC
-        LIMIT 1
-       ) AND
+      LEFT JOIN vwTradeSessionEnd AS tse ON tse.tsTicker=trsess.tsTicker
+ WHERE trsess.tsDate = tse.tsDate AND
        trins.tiType = "commodity" AND
        cntrgrp.taAttrValue LIKE "Ukraine" AND
        instgrp.taAttrValue = "energy prices" AND
        subgrp.taAttrValue = "oil/gas"

SELECT, на котором построен VIEW, выполняется ~0.8 секунд. Новый вариант запроса выполняется за 0.85 секунд, из которых 0.8 съедает этот VIEW. Короче, в качестве временного решения подойдёт.

Остаётся одна небольшая проблемка — надо внести изменения в код проекта. Начинаю искать этот SQL-запрос в коде.

Нахожу, откуда он берётся.
Бляяя.

$condition = exp::_('trsess.sessionDate')
    ->eq(exp::open(
        SqlQuery::select(array(TradeSessionModel::TABLE, 'intsess'), DBConn::GetInstance())
            ->useMap(BaseModelClass::create(TradeSessionModel::MODEL)->getPropMap())
            ->field('sessionDate')
            ->where('intsess.ticker = trsess.ticker')
            ->order('sessionDate', 'DESC')
            ->limit(1)
    )->close())
    ->land()->_('trins.type')->eq($this->instrumentType)
    ->land()->_('cntrgrp.attrValue')->like($this->countryGroup)
    ->land()->_('instgrp.attrValue')->eq($this->instrumentGroup);

if (null != $this->selectedIndex) {
    $condition = $condition->land()->_('trsess.ticker')->eq($this->selectedIndex);
}

if (null != $this->subgroup) {
    $condition = $condition->land()->_('subgrp.attrValue')->eq($this->subgroup);
}

$attrName = ('en' == $this->language) ? 'name' : 'name_'.$this->language;

$query = SqlQuery::select(array(TradeSessionModel::TABLE, 'trsess'), DBConn::GetInstance())
    ->useMap(BaseModelClass::create(TradeSessionModel::MODEL)->getPropMap())
    ->useMap(BaseModelClass::create(TradeInstrumentModel::MODEL)->getPropMap(), 'trins')
    ->useMap(BaseModelClass::create(MarketInstrumentModel::MODEL)->getPropMap(), 'mrins')
    ->useMap(BaseModelClass::create(MarketModel::MODEL)->getPropMap(), 'mrkt')
    ->useMap(BaseModelClass::create(TradeInstrumentAttrModel::MODEL)->getPropMap(), 'txt')
    ->useMap(BaseModelClass::create(TradeInstrumentAttrModel::MODEL)->getPropMap(), 'cntrgrp')
    ->useMap(BaseModelClass::create(TradeInstrumentAttrModel::MODEL)->getPropMap(), 'instgrp')
    ->useMap(BaseModelClass::create(TradeInstrumentAttrModel::MODEL)->getPropMap(), 'subgrp')
    ->useMap(BaseModelClass::create(TradeInstrumentAttrModel::MODEL)->getPropMap(), 'ord')
    ->join(array(MarketInstrumentModel::TABLE, 'mrins'), 'mrins.marketId = trsess.marketId AND mrins.ticker = trsess.ticker')
    ->join(array(MarketModel::TABLE, 'mrkt'), 'mrins.marketId = mrkt.id')
    ->join(array(TradeInstrumentModel::TABLE, 'trins'), 'mrins.instrumentId = trins.id')
    ->join(array(TradeInstrumentAttrModel::TABLE, 'txt'), 'trins.id = txt.instrumentId AND txt.attrName = ?', $attrName)
    ->join(array(TradeInstrumentAttrModel::TABLE, 'cntrgrp'), 'trins.id = cntrgrp.instrumentId AND cntrgrp.attrName = ?', 'countryGroup')
    ->join(array(TradeInstrumentAttrModel::TABLE, 'instgrp'), 'trins.id = instgrp.instrumentId AND instgrp.attrName = ?', 'group')
    ->leftJoin(array(TradeInstrumentAttrModel::TABLE, 'subgrp'), 'trins.id = subgrp.instrumentId AND subgrp.attrName = ?', 'subgroup')
    ->leftJoin(array(TradeInstrumentAttrModel::TABLE, 'ord'), 'trins.id = ord.instrumentId AND ord.attrName = ?', 'order')
    ->field('txt.attrValue', '`name`')
    ->field('mrins.currency')
    ->field('marketCode', 'exchange')
    ->field('lastPrice', 'price')
    ->field('netChange', '`change`')
    ->field('netChangePercent', '`change-pers`')
    ->field('subgrp.attrValue', 'subgroup')
    ->field('ord.attrValue', 'instrOrder')
    ->field('trsess.marketId')
    ->field('trsess.ticker')
    ->where($condition)
    ->order('cast(instrOrder as signed)');


Ебала жаба гадюку.
Tags: webdev, wtf
  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded  

  • 9 comments