Имя: Пароль:
IT
Админ
mySql. Долго выполняется запрос из-за фазы Sending data
0 DirecTwiX
 
25.03.13
17:09
В очередной раз пытаюсь оптимизировать запрос, наткнулся на странную вещь. Немного поэкспериментировав, получил такой запрос:

SELECT
     owner_id
FROM
     (SELECT
           owner_id
     FROM
           audio
     LIMIT
           1000000)a
LIMIT
     10

В профайлинге:

Starting    41 µs
Checking Permissions    5 µs
Opening Tables    13 µs
System Lock    71 µs
Optimizing    6 µs
Statistics    9 µs
Preparing    6 µs
Executing    2 µs
Sending Data    302.5 ms (99,8%)
Init    14 µs
Optimizing    3 µs
Statistics    14 µs
Preparing    5 µs
Executing    10 µs
Executing    13 µs
End    13 µs
Query End    2 µs
Closing Tables    1 µs
Removing Tmp Table    657 µs
Closing Tables    13 µs
Freeing Items    74 µs
Logging Slow Query    2 µs
Cleaning Up    4 µs

И если увеличивать внутренний лимит до 10+млн, фаза Sending data растягивается на 5 минут. О какой передаче данных идёт речь? Если выбирать из таблицы напрямую, то фаза эта будет занимать считанные доли секунд.
1 DirecTwiX
 
25.03.13
18:07
Ап
2 Fragster
 
гуру
25.03.13
18:08
получаешь через fetchall?
3 Fragster
 
гуру
25.03.13
18:08
вообще уже давно надо было понять, что внутренний селект у тебя тебе нафиг не нужен
4 Fragster
 
гуру
25.03.13
18:11
тут вот пишут, что сендинг дата - это время от начала выполнения до передачи последней строки, т.е. не только передача, но и выполнение щапроса
5 Fragster
 
гуру
25.03.13
18:11
запроса
6 DirecTwiX
 
25.03.13
18:12
(2) Что это?
(3) Запрос тестовый - разбирался откуда берётся Sending data.  В последнем предложении указал, что делал и без внутреннего селекта (т.е. это очевидно, что можно и без него)
7 Fragster
 
гуру
25.03.13
18:12
сделай EXPLAIN твойзапрос
8 DirecTwiX
 
25.03.13
18:13
(4) Есть же Executing..
Да и без внутреннего запроса Sending data вообще исчезает (сейчас проверил)
9 DirecTwiX
 
25.03.13
18:16
10 DirecTwiX
 
25.03.13
18:18
А вот для прямого запроса (запрос есть в скрине):
https://dl.dropbox.com/u/43161184/Screenshots/Capture5.PNG
11 Fragster
 
гуру
25.03.13
18:23
вот, например:

EXPLAIN SELECT score, distance, date, nickname
FROM (
SELECT score, distance, date, nickname
FROM jsgleest_results
ORDER BY id DESC
LIMIT 1000
) AS innerSelect
ORDER BY score DESC
LIMIT 10

1    PRIMARY    <derived2>    ALL    NULL    NULL    NULL    NULL    1000    Using filesort
2    DERIVED    jsgleest_results    ALL    NULL    NULL    NULL    NULL    13283    Using filesort

против

EXPLAIN SELECT score, distance, date, nickname
FROM (
SELECT score, distance, date, nickname
FROM jsgleest_results
WHERE id > (
SELECT Count( * ) -1000
FROM jsgleest_results )
) AS innerSelect
ORDER BY score DESC
LIMIT 10

1    PRIMARY    <derived2>    ALL    NULL    NULL    NULL    NULL    1016    Using filesort
2    DERIVED    jsgleest_results    ALL    PRIMARY    NULL    NULL    NULL    13283    Using where
3    SUBQUERY    NULL    NULL    NULL    NULL    NULL    NULL    NULL    Select tables optimized away


в первом случае - читается вся таблица, сортируется и уже из результатов выбирается 1000 первых, из них - выбирается 10 по другому условию. во втором - получается 1000 по первичному ключу, что на большом количестве данных быстрее
12 Fragster
 
гуру
25.03.13
18:23
(9) давай картинки целиком, а то вообще непонятно.
13 DirecTwiX
 
25.03.13
18:28
(12) Это експлейн для запроса из (0). Больше в таблице ничего нет
14 Fragster
 
гуру
25.03.13
18:30
(13) ну так он у тебя 16 миллионов строк колбасит
15 Fragster
 
гуру
25.03.13
18:32
просто запрос из (0) лишен смысла - он у тебя равнозначен
SELECT
           owner_id
     FROM
           audio
     LIMIT
           10

только без индекса
16 DirecTwiX
 
25.03.13
18:35
Так вопрос про Sending data, а не про запрос. Что он куда отправляет?
17 Fragster
 
гуру
25.03.13
18:42
(16) я ж говорю - пока запрос выполняется - сендинг дата считается
18 Fragster
 
гуру
25.03.13
18:44
а повторы есть?
19 DirecTwiX
 
25.03.13
18:55
(17) Выполнение запроса - это Executing (сендинг дата нет в прямом запросе)
(18) Нет, все разные (строки разные, но owner_id есть одинаковые. Но суть опять же в сендинг дата)
20 Fragster
 
гуру
25.03.13
18:56
(19).1 еще раз. в твоем случае - это чтение 16 мегастрок для последующего запроса. Так понятнее?
21 bahmet
 
25.03.13
19:02
мехматовцев позорят. да исчо МГУ! грусть
22 DirecTwiX
 
25.03.13
19:13
(20) Если это чтение, то понятно) Спасибо
(21) Ахаха
Что грусть то (кроме твоей логики(? Как вообще МГУ и мускуль связаны?
23 Fragster
 
гуру
25.03.13
19:17
(22) да у тебя все ветки одинаковые, и при этом одинаково странные с одинаково малосмысленными запросами
24 DirecTwiX
 
25.03.13
19:28
(23) Ветки одинаковые только из-за наличия скуля?
Везде разные вопросы.
А запрос я однажды выкладывал полный - помощи ноль было - поэтому приходится всё по частям разбирать
25 Fragster
 
гуру
25.03.13
19:32
(24) нет, ветки одинаковые из-за того, что у тебя все время запрос селект фром (селект лимит 100500) лимит 1.
26 DirecTwiX
 
25.03.13
19:34
(25) Бред. Тогда мне это нужно было, чтобы всю таблицу не тянуть и не ждать. Сейчас я разбирался почему внутренний селлект даёт сендинг дата
27 Fragster
 
гуру
25.03.13
19:37
(26) ты так ни разу и не сформулировал целиком, что ты хочешь получить, сразу лепишь селекты...
28 DirecTwiX
 
25.03.13
19:42
(27) Формулировал. Даже в первом посте выкладывал описание:
SQL. Оптимизировать ещё один запрос
29 Fragster
 
гуру
25.03.13
19:44
(28) ты хоть раз объяснил, зачем тебе лимит во внутреннем запросе? зачем там вообще внутренний запрос?
30 DirecTwiX
 
25.03.13
19:45
Только там в (3) правильный запрос.
Без внутреннего селекта у меня это дело во временную таблицу не помещается, и мускуль это всё на диск кидает. А ждать концы такого запроса не имеет смысла.
31 DirecTwiX
 
25.03.13
19:46
В той же теме и писал зачем мне внутренний запрос
32 Fragster
 
гуру
25.03.13
19:47
(31) вот это? SELECT
   A,
   COUNT(*) AS Cnt
FROM
   (SELECT
       A
   FROM
       tbl
   WHERE
       owner_id IN (SELECT DISTINCT owner_id FROM tbl WHERE A=:A)
   ) a  
GROUP BY
   A
ORDER BY
   Cnt DESC
LIMIT 10
33 DirecTwiX
 
25.03.13
19:49
(32) Да, это самый главный запрос.
До чего я дошёл - прикрутить хеш-множество в ущерб точности и скорости добавления/удаления. Но пока не сдаюсь)
34 Fragster
 
гуру
25.03.13
19:52
а почему не так?

SELECT
  A,
  COUNT(*) AS Cnt
FROM
  tbl
WHERE
  owner_id IN (SELECT DISTINCT owner_id FROM tbl WHERE A=:A)
GROUP BY
  A
ORDER BY
  Cnt DESC
LIMIT 10
35 DirecTwiX
 
25.03.13
19:56
Внутренний запрос нужен был для LIMIT. В (32) его забыл. А LIMIT нужен потому, что запрос (34) выполняется больше 10 минут
36 Fragster
 
гуру
25.03.13
20:00
(35) а EXPLAIN что выводит?
37 DirecTwiX
 
25.03.13
20:04
(36) А что он может нового вывести? Таблица на 16 млн строк. Ясен пень, что в оперативки не поместится для группировке, приходится на диск депить. Отсюда и время
38 DirecTwiX
 
25.03.13
20:04
для группировки*
39 DirecTwiX
 
25.03.13
20:04
лепить*
40 Fragster
 
гуру
25.03.13
20:08
(37) 16мегастрок после фильтрации по овнерид?
41 DirecTwiX
 
25.03.13
20:14
(40) Ошибся. Меньше конечно. Но в оперативку уже не влезает
42 Fragster
 
гуру
25.03.13
20:15
(41) прям не влезает? а какой тип у A?
43 Fragster
 
гуру
25.03.13
20:16
если у обоих int(11) то это примерно 8 байт на строку
44 DirecTwiX
 
25.03.13
20:27
45 Fragster
 
гуру
25.03.13
20:30
(44) это от (34)?
46 Fragster
 
гуру
25.03.13
20:31
т.е. победа?
47 Fragster
 
гуру
25.03.13
20:31
еще от derived избавится, заменив все на джоин можно попробовать
48 DirecTwiX
 
25.03.13
20:33
(45) Да, но только через джоин.
(46) Не сказал бы, что 20 секунд это победа - дальше база расти будет
49 Fragster
 
гуру
25.03.13
20:36
так тип-то какой?
50 Fragster
 
гуру
25.03.13
20:37
и текст запроса
51 Fragster
 
гуру
25.03.13
20:37
я вот не пойму, ты стесняешься, или думаешь, что твой запрос без данных кому-то нужен?
52 DirecTwiX
 
25.03.13
20:38
(49) Int
SELECT
   a.artist_id,
   a.title_id,
   count(*) count
FROM
   audio a
JOIN
   (SELECT DISTINCT
       owner_id
   FROM
       audio
   ".$whereClause.") owners
   ON owners.owner_id = a.owner_id
GROUP BY
   a.artist_id,
   a.title_id
LIMIT 100;
b
Where artist_id = 234
53 DirecTwiX
 
25.03.13
20:41
+order by count
54 Fragster
 
гуру
25.03.13
20:41
SELECT
  a.artist_id,
  a.title_id,
  count(*) count
FROM
  audio a
INNER JOIN audio b owners
  ON owners.owner_id = a.owner_id
   AND owners.artist_id = 234
GROUP BY
  a.artist_id,
  a.title_id
55 Fragster
 
гуру
25.03.13
20:42
INNER JOIN audio owners
56 Fragster
 
гуру
25.03.13
20:42
кстати, так хорошо все было через PDO, а тут вдруг рваный запрос...
57 DirecTwiX
 
25.03.13
20:45
(54) Джоин с той же таблицей? Эквиваленто условию WHERE a.artist_id = 234
58 DirecTwiX
 
25.03.13
20:46
Запрос выдаёт не то
59 Fragster
 
гуру
25.03.13
20:47
(58) ты проверил?
60 DirecTwiX
 
25.03.13
20:51
(59) Да
(26) В смысле "рваный запрос"? Я на yii пишу. Там удобно выполнять его
61 DirecTwiX
 
25.03.13
20:54
(59) Извиняюсь. Забыл id на более популярный сменить.
Про (57) тоже был не прав)
62 DirecTwiX
 
25.03.13
20:57
63 Fragster
 
гуру
25.03.13
20:57
(60) рваный в том смысле, что клеится из кусочков, вместо использования PDO:PreparedStatement как в SQL. Оптимизировать ещё один запрос в (0) сообщении
Это заставляет много думать про фильтрацию входных данных, т.е. тех кусочков, из которых сам запрос клеится.

(61) ну так что, получше стало?
64 Fragster
 
гуру
25.03.13
21:01
а сколько всего колонок в таблице?
65 Fragster
 
гуру
25.03.13
21:01
попробуй поменяй count(*) на sum(1)
66 DirecTwiX
 
25.03.13
21:03
(63) В yii тоже можно собирать запрос. Но т.к. у меня запросы примитивные, я даже не стал вдаваться в подробности.
Лучше особо не стало, разве только explain получше стал. Да и запрос) Возьму себе) Спасибо)
(64) Колонок 6, все инты
67 DirecTwiX
 
25.03.13
21:11
(65) Те же 90 секунд..
Это он копируует во временную таблицу для группировки?
68 DirecTwiX
 
25.03.13
21:22
И всё-таки (54) оказался косячным. Там не учитывается условие DISTINCT owners_id, и строки задваиваются
69 Fragster
 
гуру
25.03.13
22:22
интересно, что кажут

SHOW COLUMNS FROM audio

и

SHOW INDEX FROM audio
70 Fragster
 
гуру
25.03.13
22:35
ишшо надо статистику пару раз обновить - analyze table
71 DirecTwiX
 
25.03.13
22:37
Field        Type    Null    Key    Default    Extra
id        int(11)    NO    PRI    NULL    auto_increment
artist_id    int(11)    NO    MUL    NULL    
title_id    int(11)    NO    MUL    NULL    
aid        int(11)    NO        NULL    
owner_id    int(11)    NO    MUL    NULL    
duration    int(11)    NO        NULL    



Table    Non_uni    Key_name    Seq_in_index    Column_name    Collation    Cardinality    Sub_part    Packed    Null    Index_type    Comment    Index_comment
audio    0    PRIMARY        1        id        A        15952265    NULL        NULL        BTREE        
audio    1    art_tit_index    1        artist_id    A        1227097    NULL    NULL        BTREE        
audio    1    art_tit_index    2        title_id    A        3988066    NULL    NULL        BTREE        
audio    1    title_id    1        title_id    A        2658710    NULL    NULL        BTREE        
audio    1    owner_id    1        owner_id    A        60886    NULL    NULL        BTREE
72 DirecTwiX
 
25.03.13
22:39
Field    Type    Null    Key    Default    Extra
id    int(11)    NO    PRI    NULL    auto_increment
artist_id    int(11)    NO    MUL    NULL    
title_id    int(11)    NO    MUL    NULL    
aid    int(11)    NO        NULL    
owner_id    int(11)    NO    MUL    NULL    
duration    int(11)    NO        NULL    

ANALYZE TABLE audio = Table is already up to date

Спасибо за участие!) Пока решил резать число владельцев - получается вполне сносно. Дальше буду ещё думать)
73 Fragster
 
гуру
25.03.13
22:39
сделай 1 индекс на 2 поля: ownerId и artistId
74 DirecTwiX
 
25.03.13
22:43
Попробовал. Время не изменилось
75 Fragster
 
модератор
25.03.13
23:43
А по artistId отдельно?
Глупец, лишенный способности посмеяться над собой вместе с другими, не сможет долго выносить программирование. Фредерик Брукс-младший