(no subject)

Thursday, May 14th, 2009 17:05
kastaneda: (Default)
[personal profile] kastaneda
Баг-репорт: долго грузится одна из страниц сайта.

К багрепорту приложен 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)');


Ебала жаба гадюку.
(will be screened)
(will be screened if not validated)
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

September 2025

M T W T F S S
12345 67
891011121314
15161718192021
22232425262728
2930