Оптимизация MySQL: несколько режимов (наиболее распространенное значение) в одном запросе - PullRequest
0 голосов
/ 19 марта 2019

Функция моего веб-сайта по недвижимости позволяет пользователям подписываться на определенный рынок и получать регулярные обновления (называемые «анализ рынка») по электронной почте. Анализ требует, чтобы несколько значений были рассчитаны как режим (наиболее распространенное значение). Проведя некоторые исследования, я узнал, что MySQL не имеет функции MODE () , особенно потому, что может быть несколько режимов и вообще не может быть режима, а также потому, что вы даже не можете получить один режим без как минимум два значения в столбце.

Что приводит меня к этому запросу

SELECT AVG(Price) as AveragePrice,
AVG(BedroomsTotal) as AverageNumberOfBedrooms,
AVG(BathroomsTotal) as AverageNumberOfBathrooms,
AVG(SquareFeetTotal) as AverageSquareFeetTotal,
AVG(LotSize) as AverageLotSize,
AVG(AssociationFee) as AverageAssociationFee,
(SELECT PropertyType FROM (SELECT PropertyType, count(PropertyType) AS magnitude
FROM listings
GROUP BY PropertyType
ORDER BY magnitude DESC
LIMIT 1) as mpt) as MajorityPropertyType,
(SELECT magnitude FROM (SELECT PropertyType, count(PropertyType) AS magnitude
FROM listings
GROUP BY PropertyType
ORDER BY magnitude DESC
LIMIT 1) as mptc) as MajorityPropertyTypeCount,
(SELECT ArchitecturalStyle FROM (SELECT ArchitecturalStyle, count(ArchitecturalStyle) AS magnitude
FROM listings
GROUP BY ArchitecturalStyle
ORDER BY magnitude DESC
LIMIT 1) as mas) as MajorityArchitecturalStyle,
(SELECT magnitude FROM (SELECT ArchitecturalStyle, count(ArchitecturalStyle) AS magnitude
FROM listings
GROUP BY ArchitecturalStyle
ORDER BY magnitude DESC
LIMIT 1) as masc) as MajorityArchitecturalStyleCount,
AVG(YearBuilt) as AverageYearBuilt,
(SELECT PropertyCondition FROM (SELECT PropertyCondition, count(PropertyCondition) AS magnitude
FROM listings
GROUP BY PropertyCondition
ORDER BY magnitude DESC
LIMIT 1) as mpc) as MajorityPropertyCondition,
(SELECT magnitude FROM (SELECT PropertyCondition, count(PropertyCondition) AS magnitude
FROM listings
GROUP BY PropertyCondition
ORDER BY magnitude DESC
LIMIT 1) as mpcc) as MajorityPropertyConditionCount
FROM srep.active_listings 
WHERE concat(City, ', ', StateOrProvince)
LIKE "Boston, MA";

Этот запрос работает просто отлично, но проблема в том, что для его выполнения требуется 10 секунд со стоимостью запроса 11 000, и он даже не содержит доли условных операторов, которые должны быть в предложении WHERE. Есть еще 18 условных выражений, которые необходимо включить.

Вопрос (ы):

Как я могу оптимизировать этот запрос? Должен ли я использовать более новую версию MySQL? Должен ли я использовать другую базу данных в целом?

?

Текущий план выполнения

Current Execution Plan

Результаты

enter image description here

Ответы [ 2 ]

1 голос
/ 09 апреля 2019

Одним из улучшений является сокращение половины подзапросов:

    (   SELECT  PropertyType
            FROM  
            (
                SELECT  PropertyType, count(PropertyType) AS magnitude
                    FROM  listings
                    GROUP BY  PropertyType
                    ORDER BY  magnitude DESC
                    LIMIT  1) as mpt
    ) as MajorityPropertyType,

->

    (   SELECT  PropertyType
                    FROM  listings
                    GROUP BY  PropertyType
                    ORDER BY  COUNT(*) DESC
                    LIMIT  1
    ) as MajorityPropertyType

Для этого конкретного запроса потребуется INDEX(PropertyType) (если только это не PRIMARY KEY).

Еще одно улучшение - избегать скрытия индексированных столбцов в вызовах функций:

WHERE concat(City, ', ', StateOrProvince) LIKE "Boston, MA"

->

WHERE City = 'Boston' AND StateOrProvince = 'MA'

вместе с составным INDEX(City, StateOrProvince) (в любом порядке). Это позволит избежать сканирования всей таблицы, но вместо этого смотреть только на строки Бостонской MA.

Даже если бы была функция MODE, она могла бы быть не быстрее - она ​​должна была бы по сути делать то, что делает ваш код.

0 голосов
/ 21 марта 2019

Используйте другой язык (например, Python), чтобы получить режим столбца. Вот пример использования веб-API. Вам придется установить пакеты mysqlclient и flask, прежде чем этот код заработает.

App.py

import MySQLdb
import MySQLdb.cursors
from statistics import mode
from flask import Flask, jsonify

app = Flask(__name__)

RES = {}

@app.route('/')
def bar():
  conn = MySQLdb.connect('localhost', user='root', cursorclass=MySQLdb.cursors.DictCursor)
  cursor = conn.cursor()
  sql = 'SELECT ArchitecturalStyle FROM srep.active_listings'
  cursor.execute(sql)
  data = cursor.fetchall()
  row = [obj['ArchitecturalStyle'] for obj in data]
  RES["ArchitecturalStyle"] = mode(row)
  return jsonify(RES)

Тестовый запуск с использованием всех 10 атрибутов

* +1012 *Python Web API using Flask

Как видите, для получения тех же результатов в Python требуется 1/10 времени (по сравнению с MySQL).

...