Получить дополнительные данные для большого количества идентификаторов - PullRequest
1 голос
/ 25 сентября 2019

У меня есть таблица MySQL, содержащая информацию об объектах.Это выглядит так:

+--------------+----+--------+-------+
| auto_incr_id | id |  type  | value |
+--------------+----+--------+-------+
|            1 |  1 | length |   105 |
|            2 |  1 | weight |    17 |
|            3 |  1 | price  |   104 |
|            4 |  2 | length |   111 |
|            5 |  2 | weight |    18 |
|            6 |  2 | price  |    87 |
+--------------+----+--------+-------+

Я хочу получить первые x объектов, отсортированных по длине:

{
    "id": 2,
    "length": 111,
    "weight": 18,
    "price": 87
},
{
    "id": 1,
    "length": 105,
    "weight": 17,
    "price": 104
}

Вот что я делаю для достижения этой цели: во-первых, я выбираю идентификаторы:

$type = "length";
$stmt = $mysqli->prepare("SELECT id FROM table WHERE type=? ORDER BY value DESC LIMIT ?");
$stmt->bind_param('si', $type, $limit);
$stmt->execute();
$result = $stmt->get_result();
$result = $result->fetch_all(MYSQLI_ASSOC);

Далее я получаю другие значения для каждого объекта, который был выбран:

$i = 0;
while ($i < count($result)) {
    $stmt = $mysqli->prepare("SELECT type, value FROM table WHERE id=?");
    $stmt->bind_param('i', $result[$i]['id']);
    $stmt->execute();
    $result_2 = $stmt->get_result();
    $fetch = $result_2->fetch_all(MYSQLI_ASSOC);

    $j = 0;
    while ($j < count($fetch))
    {
        $result[$i][$fetch[$j]['type']] = $fetch[$j]['value'];
        $j++;
    }
}

Это прекрасно работает для выборки, например, первых 5 ($limit = 5), ноТеперь у меня есть сценарий использования, где я хочу получить эту информацию для лучших 10k или больше.Это занимает слишком много времени, вероятно потому, что нужно пройти цикл while и выполнить оператор для каждого найденного идентификатора.

Поэтому я ищу способ сократить время выполнения при получении этих данных.Есть идеи?

Ответы [ 2 ]

0 голосов
/ 25 сентября 2019

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

select id, type, value from table where id in (select id from table where type='length');

Это, очевидно, получает комбинацию типа / значения из каждого идентификатора, который имеет значение для type = 'length».Но вы не делаете это ВСЕ в базе данных.Вы все еще должны отсортировать и сгруппировать все за пределами базы данных.Предположим, у вас есть только type = 'length', 'weight' и 'price'.Я могу создать три таблицы на лету для этого, создавая атрибуты длины, веса и цены ...

select l.id, length, weight, price from
(select id, value as length from table where type='length') l
left outer join
(select id, value as weight from table where type='weight') w
on l.id=w.id
left outer join
(select id, value as price from table where type='price') p
on l.id=p.id
order by length

Теперь вы получите каждый атрибут в строке, по одной строке на идентификатор.Поле id здесь не обязательно должно быть уникальным.Если у вас один и тот же идентификатор более чем одной длины, он будет отображаться в результатах более одного раза.Но, я надеюсь, вы увидите, как я взял очевидный подзапрос и превратил его в объединение, чтобы выполнить всю работу внутри базы данных.

ПРИМЕЧАНИЕ. Я исправил ошибку неоднозначности и добавил «левый внешний», чтобы включить строкигде вес и цена не существуют.

0 голосов
/ 25 сентября 2019

Ну, по крайней мере, вы всегда можете использовать подзапрос

SELECT id, type, value FROM table 
WHERE id IN (SELECT id FROM table WHERE type=? ORDER BY value DESC LIMIT ?")
order by id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...