Как бы заставить этот запрос работать быстрее? - PullRequest
4 голосов
/ 30 июня 2011

Как бы заставить этот запрос выполняться быстрее ...?

SELECT    account_id, 
          account_name, 
          account_update, 
          account_sold, 
          account_mds, 
          ftp_url,         
          ftp_livestatus, 
          number_digits, 
          number_cw,
          client_name, 
          ppc_status, 
          user_name 
FROM     
         Accounts, 
         FTPDetails, 
         SiteNumbers, 
         Clients, 
         PPC, 
         Users 

WHERE    Accounts.account_id = FTPDetails.ftp_accountid 
AND      Accounts.account_id = SiteNumbers.number_accountid 
AND      Accounts.account_client = Clients.client_id     
AND      Accounts.account_id = PPC.ppc_accountid 
AND      Accounts.account_designer = Users.user_id   
AND      Accounts.account_active = 'active' 
AND      FTPDetails.ftp_active = 'active' 
AND      SiteNumbers.number_active = 'active' 
AND      Clients.client_active = 'active'    
AND      PPC.ppc_active = 'active'   
AND      Users.user_active = 'active' 
ORDER BY 
         Accounts.account_update DESC

Заранее спасибо:)

ОБЪЯСНИТЬ результаты запроса:

first part of table

second part of table

У меня нет никаких внешних ключей, настроенных ... Я пытался избежать внесения изменений в базу данных, так как придется сделать полныйкапитальный ремонт в ближайшее время.

идентификатором каждой таблицы являются только первичные ключи, например account_id, ftp_id, ppc_id ...

Ответы [ 4 ]

4 голосов
/ 30 июня 2011

Индексы

  • Вам необходимо - как минимум - индекс для каждого поля, которое используется в условии JOIN.

  • Индексы полей, которые появляются в предложениях WHERE или GROUP BY или ORDER BY, также в большинстве случаев полезны.

  • Когда в таблице используются два или более полей в JOIns (или WHERE или GROUP BY или ORDER BY), составной (комбинированный) индекс этих (двух или более) полей может быть лучше, чем отдельные индексы , Например, в таблице SiteNumbers возможны следующие индексы: (number_accountid, number_active) или (number_active, number_accountid).

  • Условие в полях, которые являются булевыми (ON / OFF, активный / неактивный), иногда замедляют запросы (так как индексы не являются выборочными и, следовательно, не очень полезными). В этом случае вариант реструктуризации (нормализации отца) является вариантом, но, вероятно, вы можете избежать дополнительной сложности.


Помимо обычного совета (изучите план EXPLAIN, добавьте индексы, где это необходимо, проверьте варианты запроса),

Я заметил, что в вашем запросе есть частичное декартово произведение. Таблица Accounts имеет отношение один ко многим с тремя таблицами FTPDetails, SiteNumbers и PPC. Это приводит к тому, что если у вас есть, например, 1000 учетных записей, и каждая учетная запись связана, скажем, с 10 FTPDetails, 20 SiteNumbers и 3 PPC, запрос будет возвращать для каждой учетной записи 600 строк (продукт 10x20x3). Всего 600 тыс. Строк, в которых дублируется много данных.

Вместо этого можно разделить запрос на три плюс один для базовых данных (учетная запись и остальные таблицы). Таким образом, будет передано только 34K строк данных (имеющих меньшую длину):

Accounts JOIN Clients JOIN Users 
  (with all fields needed from these tables)
  1K rows

Accounts JOIN FTPDetails
  (with Accounts.account_id and all fields from FTPDetails)
  10K rows

Accounts JOIN SiteNumbers
  (with Accounts.account_id and all fields from SiteNumbers)
  20K rows

Accounts JOIN PPC
  (with Accounts.account_id and all fields from PPC)
  3K rows

и затем использовать данные из 4 запросов на стороне клиента для отображения объединенной информации.



Я бы добавил следующие индексы:

Table Accounts
  index on (account_designer)
  index on (account_client)
  index on (account_active, account_id)
  index on (account_update)

Table FTPDetails
  index on (ftp_active, ftp_accountid)

Table SiteNumbers
  index on (number_active, number_accountid)

Table PPC
  index on (ppc_active, ppc_accountid)
3 голосов
/ 30 июня 2011

Используйте EXPLAIN , чтобы узнать, какой индекс можно использовать и какой индекс фактически используется. При необходимости создайте соответствующий индекс.

Если FTPDetails.ftp_active имеет только две действительные записи 'active' и 'inactive', используйте BOOL в качестве типа данных.

В качестве примечания: я настоятельно рекомендую использовать явные объединения вместо неявных:

SELECT
  account_id, account_name, account_update, account_sold, account_mds, 
  ftp_url, ftp_livestatus, 
  number_digits, number_cw,
  client_name, 
  ppc_status, 
  user_name 
FROM Accounts 
INNER JOIN FTPDetails
  ON  Accounts.account_id = FTPDetails.ftp_accountid
  AND FTPDetails.ftp_active = 'active'
INNER JOIN SiteNumbers
  ON  Accounts.account_id = SiteNumbers.number_accountid 
  AND SiteNumbers.number_active = 'active'
INNER JOIN Clients
  ON  Accounts.account_client = Clients.client_id
  AND Clients.client_active = 'active'
INNER JOIN PPC
  ON  Accounts.account_id = PPC.ppc_accountid
  AND PPC.ppc_active = 'active'
INNER JOIN Users
  ON  Accounts.account_designer = Users.user_id
  AND Users.user_active = 'active'
WHERE Accounts.account_active = 'active' 
ORDER BY Accounts.account_update DESC

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

0 голосов
/ 30 июня 2011

Одна из ваших главных проблем здесь: x.y_active = 'active'

Проблема: низкая мощность
Активное поле - это логическое поле с 2 возможными значениями, поэтому оно имеет очень низкую мощность. MySQL (или любой SQL в этом отношении не будет использовать индекс, если 30% или более строк имеют одинаковое значение).
Форсировать индекс бесполезно, потому что он сделает ваш запрос медленнее, а не быстрее.

Решение: разделите ваши таблицы
Решение состоит в том, чтобы разбить ваши таблицы на столбцы active.
Это исключит все неактивные поля из рассмотрения и заставит select действовать так, как будто у вас действительно есть рабочий индекс для полей xxx-active.

Sidenote
Пожалуйста, никогда не используйте неявные where объединения, это слишком чревато ошибками и потребляет, чтобы быть полезным.
Вместо этого используйте синтаксис, такой как ответ Освальда .

Ссылки:
Количество элементов: http://en.wikipedia.org/wiki/Cardinality_(SQL_statements)
Количество элементов и индексы: http://www.bennadel.com/blog/1424-Exploring-The-Cardinality-And-Selectivity-Of-SQL-Conditions.htm
Разделение MySQL: http://dev.mysql.com/doc/refman/5.5/en/partitioning.html

0 голосов
/ 30 июня 2011

ОБЪЯСНЯЙТЕ, тестируйте разные варианты. Для начала, я уверен, что несколько запросов будут быстрее, чем этот монстр. Во-первых, потому что оптимизатор запросов будет тратить много времени на изучение того, какой порядок соединения является лучшим (5! = 120 возможностей). Во-вторых, запросы типа SELECT ... WHERE ....active = 'active' будут кэшироваться (хотя это зависит от количества изменений данных).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...