Оптимизация mysql - отображает 10 самых последних записей, а также выявляет повторяющиеся строки - PullRequest
3 голосов
/ 03 февраля 2010

Я новичок в mysql и уже несколько дней тяну волосы за эту проблему.Мне нужно улучшить / оптимизировать этот запрос, чтобы он выполнялся быстрее - сейчас он занимает более 5 секунд.

Вот запрос:

SELECT SQL_NO_CACHE COUNT(*) as multiple, a.*,b.*  
FROM announcements as a  
INNER JOIN stores as s  
ON a.username=s.username
    WHERE s.username is not null AND s.state='NC' 
GROUP BY a.announcement_id
ORDER BY a.dt DESC LIMIT 0,10

Магазины Таблица состоит из: store_id, имени пользователя, имени, штата, города, почтового индекса и т. Д. ...

Объявления таблица состоит из: messages_id, msg, dt, имени пользователя

Таблица магазинов содержит около 10 000 записей, а таблица объявлений - около 500 000 записей.

ЧтоЯ пытаюсь выполнить по-английски - отобразить 10 самых последних объявлений магазина, НО это усложняет то, что магазины могут иметь несколько записей в таблице магазинов с одинаковым идентификатором пользователя (по одной строке на местоположение).Так что, если сеть магазинов, скажем, «Chipotle» отправляет объявление, я хочу отобразить только одну строку для их объявления с примечанием рядом с ним, которое говорит, что «этот магазин имеет несколько мест».Вот почему я использую count (*) и group by, поэтому, если count(*) > 1 я знаю, что для объявления есть несколько мест.

Условием where может быть любой штат, город или почтовый индекс.Использование SQL_NO_CACHE, потому что объявления часто обновляются, поэтому вы редко получаете одинаковые результаты, имеет ли это смысл?

Буду очень признателен за любые предложения о том, как сделать это лучше.Я мало знаю об индексах, но я создал индекс для поля «имя пользователя» в обеих таблицах.Не стесняйтесь меня уничтожить, я знаю, что что-то упустил.

Обновление -

DESC магазины;

Field       Type            Null    Key     Default         Extra  
store_id    int(11)         NO      PRI     NULL            auto_increment  
username    varchar(20)     NO      MUL     NULL       
name        varchar(100)    NO              NULL       
street      varchar(100)    NO              NULL       
city        varchar(50)     NO              NULL       
state       varchar(2)      NO              NULL       
zip         varchar(15)     NO              NULL      

Объявления DESC;

Field              Type           Null      Key     Default     Extra
dt                 datetime       NO                NULL     
username           varchar(20)    NO        MUL     NULL     
msg                varchar(200)   NO                NULL     
announcement_id    int(11)        NO        PRI     NULL        auto_increment

EXPLAIN output;

id  select_type     table   type    possible_keys   key       key_len     ref         rows     Extra
1   SIMPLE          a       index   username        PRIMARY   47          NULL        315001   Using temporary; Using filesort
1   SIMPLE          b       ref     username        username  62          a.username  1        Using where

Ответы [ 3 ]

2 голосов
/ 04 февраля 2010

Попробуйте что-то вроде этого:

SELECT SQL_NO_CACHE COUNT(*) as multiple, a.*,b.*   
FROM announcements as a   
INNER JOIN 
(
  SELECT username, COUNT(username) as multiple FROM stores
  WHERE username IS NOT NULL AND state = 'NC'
  GROUP BY username
 )  as s 
ON a.username=s.username 
ORDER BY a.dt DESC LIMIT 10 
0 голосов
/ 07 февраля 2010
  • Измените порядок таблиц в вашем JOIN, MySQL читает строки из первой таблицы, а затем находит совпадающие строки во второй таблице. Если вы всегда фильтруете свой результат по полям в таблице магазинов, то таблица магазинов должна быть ведущей таблицей в вашем JOIN, чтобы она не выбирала и не сортировала ненужные строки из таблицы объявлений.
    В выводе EXPLAIN, который вы вставили, кажется, что только один магазин соответствует запросу, переключение порядка таблиц приведет к тому, что он будет искать только этот конкретный магазин в таблице объявлений.
  • Добавить индекс для столбца dt (было бы еще лучше иметь индексированный целочисленный столбец с unixtime)
  • Если возможно - создайте целочисленный userID для каждого имени пользователя и JOIN, используя этот столбец (также добавьте индекс on для него)
  • Не уверен, что MySQL все еще имеет проблемы с этим, но замена COUNT (*) на COUNT (1) может быть полезной.
0 голосов
/ 05 февраля 2010

Если вы упорядочиваете по столбцу dt, но для этого столбца нет индекса, MySQL должен будет выполнять (медленную, дорогую) сортировку всех ваших строк результатов в этом столбце каждый раз, когда вы запускаете запрос

Попробуйте добавить индекс на announcements.dt - MySQL может получить доступ к строкам по порядку, используя индекс, и впоследствии избежать шага сортировки.

...