За последние 24 часа нас посетили 35864 программиста и 1662 робота. Сейчас ищут 1189 программистов ...

Сложная Выборка

Тема в разделе "MySQL", создана пользователем neverlose, 17 сен 2010.

  1. neverlose

    neverlose Активный пользователь

    С нами с:
    27 авг 2008
    Сообщения:
    1.112
    Симпатии:
    20
    Есть массив чисел (по сути - id'шки категорий, классификаторов и их значений).
    Например:
    PHP:
    1. $data = array(
    2.     array(
    3.         'category_id' => 5,
    4.         'clf_id' => 7,
    5.         'clf_value' => 2
    6.     ),
    7.     array(
    8.         'category_id' => 3,
    9.         'clf_id' => 4,
    10.         'clf_value' => 0
    11.     ),
    12. );

    Есть таблица с полями

    category_id clf_id clf_value, все поля имеют тип unsigned int NULL

    Задача:
    Написать запрос, возвращающий id категорий, поля которых указаны в таблице (то есть совпадения 3 значений массива совпадают с тремя значениями полей в строке таблицы, соответственно). При этом, также нужно вернуть id категорий, которые есть в массиве, но нет в базе с заданным классификатором (то есть если совпала category_id и clf_id но нет совпадения clf_value) - то возвращать не нужно, однако, если если совпала category_id, но нет совпадений с clf_id - возвращаем id категории, И ещё нужно вернуть id категорий у которого значение классификатора = NULL если произошло совпадение по первым двум полям (category_id, clf_id), И ещё возвратить нужно id категорий, которые есть в заданном массиве но нет в таблице вовсе. Ну и всё это должно работать оптимизировано.

    Пока реализовал с помощью 15 join'ov скорость запроса колеблется в районе 4 секунд на 5000 записей.

    Было бы интересно посмотреть на ваши прототипы и идеи.
     
  2. Gromo

    Gromo Активный пользователь

    С нами с:
    24 май 2010
    Сообщения:
    2.786
    Симпатии:
    2
    Адрес:
    Ташкент
    ИМХО, если запрос содержит больше 2-3 join-ов на ту же самую таблицу, то его нужно пересматривать.
    Думаю, что следует разбить это запрос на несколько - по одному для каждой задачи.
    А дальше смотреть по ситуации - может какие-то объеденить, другие - оптимизировать.
     
  3. neverlose

    neverlose Активный пользователь

    С нами с:
    27 авг 2008
    Сообщения:
    1.112
    Симпатии:
    20
    Написал так, по-моему работает, и быстро.
    PHP:
    1.  
    2. <?php
    3.     public function getFilteredCatIds()
    4.     {
    5.         $this->_name = 'shop_catalogue_classifiers_values';
    6.  
    7.         $PetID = $animalId = false;
    8.         $sess  = new Zend_Session_Namespace( 'ZooZNS');
    9.  
    10.         if( empty( $sess->animal_id))
    11.         {
    12.             $animals = new AnimalsModel();
    13.             $PetID = $animals->getActivePetID();
    14.             $petInfo = $animals->getPetCoditionFields( $PetID);
    15.         }
    16.         else
    17.             $animalId = $sess->animal_id;
    18.  
    19.         // Getting all available catalogues
    20.         $shop = new ShopCatalogueModel();
    21.         $catalogues = $shop->GetAllByType('C');
    22.  
    23.         if( !$total = count( $catalogues))
    24.             return $catalogues;
    25.  
    26.         $select = $this->select()->SetIntegrityCheck( false)->distinct()
    27.                       ->from( array( 'a' => $this->_name), array('a.catalogue_id'))
    28.                       ->where('a.catalogue_id IN(?)', $catalogues);
    29.         if( $PetID)
    30.         {
    31.             // Животное
    32.             $select = $select->where('clf_id = 59 AND clf_value IN(0,' .$petInfo['AnimalID'] .')');
    33.  
    34.             // Размер
    35.             if( !empty( $petInfo['SizeID']))
    36.                 $select = $select->where('clf_id = 52 AND clf_value IN(0,' .$petInfo['SizeID'] .')');
    37.  
    38.             // Возраст может, в IN() 0 не нужен?
    39.             if( !empty( $petInfo['Birthday']))
    40.             {
    41.                 $year  = date('Y');
    42.                 $month = date('m');
    43.                 $total_month = $year * 12 + $month;
    44.  
    45.                 $info = explode('-', $petInfo['Birthday']);
    46.  
    47.                 $pet_year  = $info[0];
    48.                 $pet_month = $info[1];
    49.                 $total_pet_month = $pet_year * 12 + $pet_month;
    50.  
    51.                 $pet_age_in_months = $total_month - $total_pet_month;
    52.  
    53.                 $periods_model = new PeriodsModel();
    54.                 $petInfo['Birthday'] = $periods_model->getPeriodIds( $pet_age_in_months);
    55.                 $select = $select->where('clf_id = 60 AND clf_value IN(0,' .$petInfo['Birthday'] .')');
    56.             }
    57.  
    58.             // Порода
    59.             if( !empty( $petInfo['BreedID']))
    60.                 $select = $select->where('clf_id = 50 AND clf_value IN(0,' .$petInfo['BreedID'] .')');
    61.  
    62.             // Цвет шерсти
    63.             if( !empty( $petInfo['WoolColorID']))
    64.                 $select = $select->where('clf_id = 56 AND clf_value IN(0,' .$petInfo['WoolColorID'] .')');
    65.  
    66.             // Тип шерсти
    67.             if( !empty( $petInfo['WoolTypeID']))
    68.                 $select = $select->where('clf_id = 57 AND clf_value IN(0,' .$petInfo['WoolTypeID'] .')');
    69.  
    70.             // Колтуны
    71.             if( !empty( $petInfo['MatsID']))
    72.                 $select = $select->where('clf_id = 58 AND clf_value IN(0,' .$petInfo['MatsID'] .')');
    73.  
    74.             // Чувствительность кожи
    75.             if( !empty( $petInfo['SkinID']))
    76.                 $select = $select->where('clf_id = 53 AND clf_value IN(0,' .$petInfo['SkinID'] .')');
    77.  
    78.             // Где живёт
    79.             if( !empty( $petInfo['WhereLivesID']))
    80.             {
    81.                 $wla = new WherelivesanimalModel();
    82.                 $lives = $wla->getSingle( array( 'WhereLivesID'), 'id = ' .$petInfo['WhereLivesID']);
    83.                 $petInfo['WhereLivesID'] = $lives['WhereLivesID'];
    84.  
    85.                 $select = $select->where('clf_id = 54 AND clf_value IN(0,' .$petInfo['WhereLivesID'] .')');
    86.             }
    87.             // Образ жизни
    88.             elseif( !empty( $petInfo['WayOfLifeID']))
    89.                 $select = $select = $select->where('clf_id = 54 AND clf_value IN(0,' .$petInfo['WayOfLifeID'] .')');
    90.         }
    91.         elseif( $animalId)
    92.         {
    93.             // Животное
    94.             $select = $select->where('clf_id = 59 AND clf_value IN(0,' .$animalId .')');
    95.         }
    96.         $data   = $this->getAdapter()->fetchAll( $select);
    97.  
    98.         $found = array();
    99.         if( !empty( $data))
    100.         {
    101.             foreach( $data as $row)
    102.                 $found[] = $row['catalogue_id'];
    103.         }
    104.  
    105.         if( count( $found) == $total)
    106.             return $found;
    107.  
    108.         $catalogues = array_diff( $catalogues, $found);
    109.  
    110.  
    111.  
    112.  
    113.  
    114.         /////////// Creating query, to select records, which MUST NOT be in the result
    115.         $select = $this->select()->SetIntegrityCheck( false)->distinct()
    116.                       ->from( array( 'a' => $this->_name), array('a.catalogue_id'))
    117.                       ->where('a.catalogue_id IN(?)', $catalogues);
    118.         if( $PetID)
    119.         {
    120.             // Животное
    121.             $select = $select->where('clf_id = 59 AND clf_value NOT IN(0,' .$petInfo['AnimalID'] .')');
    122.  
    123.             // Размер
    124.             if( !empty( $petInfo['SizeID']))
    125.                 $select = $select->where('clf_id = 52 AND clf_value NOT IN(0,' .$petInfo['SizeID'] .')');
    126.  
    127.             // Возраст может, в IN() 0 не нужен?
    128.             if( !empty( $petInfo['Birthday']))
    129.             {
    130.                 $select = $select->where('clf_id = 60 AND clf_value NOT IN(0,' .$petInfo['Birthday'] .')');
    131.             }
    132.  
    133.             // Порода
    134.             if( !empty( $petInfo['BreedID']))
    135.                 $select = $select->where('clf_id = 50 AND clf_value NOT IN(0,' .$petInfo['BreedID'] .')');
    136.  
    137.             // Цвет шерсти
    138.             if( !empty( $petInfo['WoolColorID']))
    139.                 $select = $select->where('clf_id = 56 AND clf_value NOT IN(0,' .$petInfo['WoolColorID'] .')');
    140.  
    141.             // Тип шерсти
    142.             if( !empty( $petInfo['WoolTypeID']))
    143.                 $select = $select->where('clf_id = 57 AND clf_value NOT IN(0,' .$petInfo['WoolTypeID'] .')');
    144.  
    145.             // Колтуны
    146.             if( !empty( $petInfo['MatsID']))
    147.                 $select = $select->where('clf_id = 58 AND clf_value NOT IN(0,' .$petInfo['MatsID'] .')');
    148.  
    149.             // Чувствительность кожи
    150.             if( !empty( $petInfo['SkinID']))
    151.                 $select = $select->where('clf_id = 53 AND clf_value NOT IN(0,' .$petInfo['SkinID'] .')');
    152.  
    153.             // Где живёт
    154.             if( !empty( $petInfo['WhereLivesID']))
    155.                 $select = $select->where('clf_id = 54 AND clf_value NOT IN(0,' .$petInfo['WhereLivesID'] .')');
    156.  
    157.             // Образ жизни
    158.             elseif( !empty( $petInfo['WayOfLifeID']))
    159.                 $select = $select = $select->where('clf_id = 54 AND clf_value NOT IN(0,' .$petInfo['WayOfLifeID'] .')');
    160.         }
    161.         elseif( $animalId)
    162.         {
    163.             // Животное
    164.             $select = $select->where('clf_id = 59 AND clf_value NOT IN(0,' .$animalId .')');
    165.         }
    166.         $data   = $this->getAdapter()->fetchAll( $select);
    167.  
    168.         $found2 = array();
    169.         if( !empty( $data))
    170.         {
    171.             foreach( $data as $row)
    172.                 $found2[] = $row['catalogue_id'];
    173.         }
    174.  
    175.         if( count( $found2))
    176.             $catalogues = array_diff( $catalogues, $found2);
    177.         $result = array_merge( $catalogues, $found);
    178.  
    179.  
    180.  
    181.  
    182.         $this->_name = 'shop_catalogue_classifiers';
    183.  
    184.         return $result;
    185.     }
    186. ?>
    187.  
     
  4. Gromo

    Gromo Активный пользователь

    С нами с:
    24 май 2010
    Сообщения:
    2.786
    Симпатии:
    2
    Адрес:
    Ташкент
    если считаешь, что работает быстро - то это хорошо.

    а то мне легче пойти и побиться голой о ближайшую стенку,
    чем попытаться разобраться в этом :)

    код красивый, но за 5 мин не осилю, а больше 5 мин жалко тратить на чужой код :)