За последние 24 часа нас посетили 16584 программиста и 1621 робот. Сейчас ищут 1088 программистов ...

Помогите с запросом

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

  1. Penegan

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

    С нами с:
    6 апр 2009
    Сообщения:
    44
    Симпатии:
    0
    Есть несколько таблиц:
    1) `country`Содержит название стран и их ключ (id , name)
    2) `city` Содержит название городов их ключи и ключи стран (id, name, contryId)
    3) `company` Название фирм и ключи фирм (id, name)
    ...
    ...
    n) `car` Таблица товаров (id, name ,countryId, cityId, сompanyId, price, .....)

    Тужно сделать выборку товаров, где стоимость < 2000$, типа: 1 - Автомобиль - Германия - Берлин - 1999$

    Я представляю как это сделать с помощью нескольких запросов:
    [sql]"SELECT * FROM `car` WHERE `price` < 2000"[/sql]
    Далее для каждого из результатов узнавать название Страны, города и фирмы
    [sql]"SELECT `name` FROM `city` WHERE id = .."
    "SELECT `name` FROM `country` WHERE id = .."
    "SELECT `name` FROM `company` WHERE id = .."
    ....[/sql]

    Ну это, наверное, глупо, так как характеристик товаров у меня больше 10:)
    Возможно ли объединить эти запросы в один?

    Заранее спасибо за ответ...
     
  2. Simpliest

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

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    [sql]SELECT * FROM table
    JOIN table1 ON table1.id = table.myTable1Id
    JOIN table2 ON table2.id = table.myTable2Id
    ....[/sql]
    Только поля с одинаковыми именами в разных таблицах необходимо будет перечислить вместо * и указать им алиасы.
     
  3. Penegan

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

    С нами с:
    6 апр 2009
    Сообщения:
    44
    Симпатии:
    0
    Спасибо за пример!
    Нашел еще один вариант реализации:
    [sql]
    SELECT table1.name AS name, table2.name AS name2 .....
    FROM `table`, `table1`, `table2`....
    WHERE table1.id = table.myTable1Id AND table1.id = table.myTable1Id ....
    [/sql]
     
  4. Simpliest

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

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Это просто другая форма синтаксиса JOIN и работает не во всех БД

    Лучше его записывать явно. Поскольку есть варианты JOIN - LEFT, RIGHT, CROSS, FULL и много других.
    http://en.wikipedia.org/wiki/Join_(SQL)
     
  5. Penegan

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

    С нами с:
    6 апр 2009
    Сообщения:
    44
    Симпатии:
    0
    Понятно, спасибо
     
  6. Penegan

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

    С нами с:
    6 апр 2009
    Сообщения:
    44
    Симпатии:
    0
    Пришел к выводу, что в моем случает соединять таблицы не лучший вариант:)
    Строк в главной таблице более 10 млн( > 1 Гб), и обработка запроса занимала около 40сек.
    Пришлось принимать меры, для начала поменял тип всех значений с главной таблицы на числовой, что привело к созданию парочки дополнительных справочных таблиц.

    Решил создать 1 запрос, который будет выбирать из базы 10 записей, по условиям, которые задает пользователь
    [sql]
    SELECT `val1`, `val2`, ....
    FROM `table`
    WHERE `term1`, `term2` .....
    LIMIT 0, 10
    [/sql]

    И уже по этим 10 записям делать выборку с остальных таблиц...

    Результат получился неоднозначным :)
    Когда пользователь задает условия, при которых 10 записей находятся быстро, то скорость 2-8 сек.
    Но если задает такие, записей по которым в таблице < 10, или задает сортировку
    [sql]
    ORDER BY `val1` ASC
    [/sql]
    то скорость опять поднимается до 40 сек.

    Существует ли методы в mysql для сокращения работы с таким количеством данных?

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

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

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Penegan
    структуру БД давай сюда. И описание что в ней хранится и в каком количестве.
     
  8. Penegan

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

    С нами с:
    6 апр 2009
    Сообщения:
    44
    Симпатии:
    0
    Сайт туристического агенства.
    Есть таблица туров (цена, дата вылета, страна, город вылета, город прилета, курорт .....) все по чем будет идти выборка заданы в числовом формате.
    [sql]CREATE TABLE `tours` (
    `P` mediumint(9) NOT NULL,
    `D` int(11) NOT NULL,
    `aFCK` mediumint(9) NOT NULL,
    `aTCK` mediumint(9) NOT NULL,
    `htlBK` mediumint(9) NOT NULL,
    `htlK` mediumint(9) NOT NULL,
    `htlCoK` mediumint(9) NOT NULL,
    `htlCiK` mediumint(9) NOT NULL,
    `htlRK` mediumint(9) NOT NULL,
    `htlCN` text,
    `htlN` mediumint(9) NOT NULL,
    `htlD` mediumint(9) NOT NULL,
    `htlM` mediumint(9) NOT NULL,
    `roomTK` mediumint(9) NOT NULL,
    `roomAK` mediumint(9) NOT NULL,
    `roomNA` mediumint(9) NOT NULL,
    `roomNC` mediumint(9) NOT NULL,
    `roomCK` mediumint(9) NOT NULL,
    `operator` text,
    `SPO` int(11) NOT NULL,
    `key` int(11) NOT NULL,
    PRIMARY KEY (`key`)
    )[/sql]
    Количество записей меняется, в зависимости от срока действия, в пределах 9 - 12 млн. туров. Весом где-то 0,9-1,2 Гб

    Таблицы справочников, где связываются id городов, стран, гостиниц... с их именами.
    Аналогичные этой:
    [sql]
    CREATE TABLE `country` (
    `Key` int(11) NOT NULL,
    `Name` text,
    `NameLat` text,
    PRIMARY KEY (`Key`)
    )
    [/sql]

    Соответственно нужно при заданных параметрах поиска вывести результат.
    В поиск обязательно включены параметры `Стана` и `Город вылета`, все остальные могут не иметь значений, то есть не возможно задать запрос типа `вывести все туры`.
    [sql]
    SELECT `P`, `D`, `htlCoK`, `htlK`, ....
    FROM `tours`
    WHERE `aFCK` = $_POST['cityFrom'] AND `htlCoK` = $_POST['country']
    ORDER BY `P` ASC
    LIMIT 0,10
    [/sql]
    Такой вот запрос выполняется около 40 сек


    Выходя из этого, можно разделить таблицу `tours` на несколько меньших, допустим `tours_egypt`, `tours_turkey`.... или на `tours_city1_to_egypt`, `tours_city2_to_turkey` ....
    И уже в зависимости от выбранной страны искать в нужной таблице...

    Думаю это приведет к определенной оптимизации...

    Есть ли еще способы сократить время выборки?
     
  9. Simpliest

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

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Сейчас посмотрим.

    EXPLAIN на запросы делал?

    И в MySQL что говорят тебе эти два лога?

    log-slow-queries = D:/Web/mysql_slow_query.log
    log-queries-not-using-indexes = D:/Web/mysql_query_nui.log
     
  10. Penegan

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

    С нами с:
    6 апр 2009
    Сообщения:
    44
    Симпатии:
    0
    С explain не знаком, поэтому не делал)

    На счет логов, те, которые вы указали, хостер походу не дает, есть следующие:

    hardqueries.log
    mysqlusage.log
    cpuusing.log
     
  11. Simpliest

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

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    посмотри его.

    Значит есть повод познакомиться.

    Делается
    EXPLAIN тут твой обычный запрос

    например
    [sql]EXPLAIN SELECT `P`, `D`, `htlCoK`, `htlK`, ....
    FROM `tours`
    WHERE `aFCK` = $_POST['cityFrom'] AND `htlCoK` = $_POST['country']
    ORDER BY `P` ASC
    LIMIT 0,10[/sql]

    Сейчас, я базу набью, посмотрим что происходит

    Хотя первое что очевидно сразу это добавить индексы по `aFCK`,`htlCoK`
     
  12. Penegan

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

    С нами с:
    6 апр 2009
    Сообщения:
    44
    Симпатии:
    0
    hardqueries.log
    Код (Text):
    1.  
    2. DATE: 2010-02-04 11:54:04
    3. PID: 29448 %CPU: 30.2% %MEM: 4.7% VSZ: 307628 kB RSS: 283356 STAT: S TIME: 1:03
    4. SCRIPT: .../update/uploadSPO.php
    5. Query String: 0
    6. Remote Address: 188.163.129.248
    uploadSPO.php - это скрипт загрузки в БД туров у туроператора.
    Информации о скрипте, который делает выборку тут нет.

    EXPLAIN:
    [sql]
    id select_type table type possible_keys key key_len ref rows Extra
    1 SIMPLE tours ALL NULL NULL NULL NULL 10440705 Using where; Using filesort
    [/sql]
     
  13. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    Simpliest
    Индексы? Или один индекс включающий оба столбца?
     
  14. Simpliest

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

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    самое нехорошее, что может быть на больших выборках.

    Начинай тыкать индексы по полям. Добавь два что я сказал и попробуй сделать EXPLAIN для своего запроса опять

    Зависит от запросов.
     
  15. Simpliest

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

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Так, ну что я могу сказать. Залил я базу.
    15млн записей

    первые два запрос без индексов
    3й и 4й с двумя отдельными индексами по полям aFCK,htlCoK
    Код (Text):
    1. mysql> show profiles;
    2. +----------+-------------+---------------------------------------------------------+
    3. | Query_ID | Duration    | Query                                                   |
    4. +----------+-------------+---------------------------------------------------------+
    5. |        1 | 60.47279750 | select * from tours where aFCK = 101 and htlCoK = 102   |
    6. |        2 | 62.95918725 | select * from tours where aFCK = -101 and htlCoK = -202 |
    7. |        3 |  1.13012300 | select * from tours where aFCK = 101 and htlCoK = 102   |
    8. |        4 |  0.88023450 | select * from tours where aFCK = -101 and htlCoK = -202 |
    9. +----------+-------------+---------------------------------------------------------+
    10. 4 rows in set (0.00 sec)
     
  16. Penegan

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

    С нами с:
    6 апр 2009
    Сообщения:
    44
    Симпатии:
    0
    Круто, в 60 раз быстрее получается)

    Спасибо за потраченное время!

    Индексы установить не удалось, слишком долгий процесс, браузер завершал работу...)

    Решил перезалить базу туров, уже в несколько таблиц с индексами.

    Еще раз огромное спасибо)
     
  17. Simpliest

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

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    это делается не через браузер, а через ssh или консоль.

    у меня индексы ставились примерно 15-20минут.

    комбинированный все еще ставится вот уже скоро час
     
  18. Simpliest

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

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Гадство, на что я подписался :)

    Оно все еще строит его 4й час пошел.
     
  19. Теоретически, если перед навешиванием индекса залочить табличку на запись - будет быстрее. Не уверен, что в мускуле это так, но...
     
  20. Костян

    Костян Активный пользователь

    С нами с:
    12 ноя 2009
    Сообщения:
    1.724
    Симпатии:
    1
    Адрес:
    адуктО
    Теоретически индексы надо ставить на пустые таблицы ;)
     
  21. Penegan

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

    С нами с:
    6 апр 2009
    Сообщения:
    44
    Симпатии:
    0
    Только что закончил подгрузку туров в новые таблицы с индексами, поиск осуществляется моментально (0,08 сек) :)
     
  22. Костян

    Костян Активный пользователь

    С нами с:
    12 ноя 2009
    Сообщения:
    1.724
    Симпатии:
    1
    Адрес:
    адуктО
    Penegan
    вообще лучше почитай, как правильно ставить индексы, то есть по каким полям и т.д, чтобы эти вопросы ту уже знал.
     
  23. Simpliest

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

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Добавка

    Код (Text):
    1. |        5 |  0.66462750 | select * from tours where aFCK = -101 and htlCoK = -202 |
    2. |        6 |  0.68352100 | select * from tours where aFCK = 101 and htlCoK = 102   |
    3. +----------+-------------+---------------------------------------------------------+
    Код (Text):
    1.  
    2. mysql> explain select * from tours where aFCK = -101 and htlCoK = -202;
    3. +----+-------------+-------+------+----------------------+----------+---------+-------------+------+-------+
    4. | id | select_type | table | type | possible_keys        | key      | key_len | ref         | rows | Extra |
    5. +----+-------------+-------+------+----------------------+----------+---------+-------------+------+-------+
    6. |  1 | SIMPLE      | tours | ref  | afck,htlcok,combined | combined | 6       | const,const |   39 |       |
    7. +----+-------------+-------+------+----------------------+----------+---------+-------------+------+-------+
    8. 1 row in set (0.05 sec)
    9.  
    10. mysql> explain select * from tours where aFCK = 101 and htlCoK = 102;
    11. +----+-------------+-------+------+----------------------+----------+---------+-------------+------+-------+
    12. | id | select_type | table | type | possible_keys        | key      | key_len | ref         | rows | Extra |
    13. +----+-------------+-------+------+----------------------+----------+---------+-------------+------+-------+
    14. |  1 | SIMPLE      | tours | ref  | afck,htlcok,combined | combined | 6       | const,const |   56 |       |
    15. +----+-------------+-------+------+----------------------+----------+---------+-------------+------+-------+
    16. 1 row in set (0.00 sec)
    Собственно для данных двух конкретных запросов комбинированный индекс лучше примерно на 60%
     
  24. Simpliest

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

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Возможно, но проверять мне лень уже :)

    Тогда мне не удалось бы снять слепок работы без индексов :)

    таблица 15млн записей.
    в среднем в выборке получается по 300к записей при группировке по 2м полям.
     
  25. Penegan

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

    С нами с:
    6 апр 2009
    Сообщения:
    44
    Симпатии:
    0
    как раз перед тем как их поставить так и сделал, чтоб потом не переделывать:)