Медленный запрос с использованием MySql, EF и CF

У меня есть запрос, который занимает почти 2 минуты. Можете ли вы дать мне совет, как его улучшить? Дизайн базы данных, как вы можете видеть в классе Ads, не очень хорош... возможно ли оптимизировать запрос без изменения типов столбцов?

Я могу изменить AdStatus столбец в целое число легко... но изменить OperationType а также AdType потребует большой миграции. Кстати, я пытался сделать запрос, просто используя значения широты и долготы, и он также был очень медленным.

Ads таблица имеет 2,3 миллиона предметов, а Pictureads таблица имеет 11 миллионов предметов

Я использую Amazon RDS t2.micro

Также, если вы видите в модели что-то, что необходимо изменить, пожалуйста, дайте мне знать

var queryResults = (from d in ApplicationContext.Ads.AsNoTracking()
    where (d.Latitude >= latitude - radio)
    && (d.AdStatus != "Pending")
    && (d.Latitude <= latitude + radio)
    && (d.Longitude >= longitude - radio)
    && (d.Longitude <= longitude + radio)
    && (String.IsNullOrEmpty(operationType) || d.OperationType == operationType)
    && (!(priceMax > priceMin && (priceMin > 0 || priceMax > 0)) || (d.USDPrice >= priceMin && d.USDPrice <= priceMax))
    && (String.IsNullOrEmpty(adType) || d.AdType == adType)
    orderby d.USDPrice ascending
    select new
    {
        d.AdsID,
        d.Username,
        d.administrative_area_level_1,
        d.administrative_area_level_2,
        d.administrative_area_level_3,
        d.neighborhood,
        d.Address,
        d.PictureUrl,
        d.Latitude,
        d.Longitude,
        d.ExpirationDate,
        d.FeaturedAd,
        d.PremiumAd,
        d.Views,
        d.Code,
        d.OperationType,
        d.Price,
        d.USDPrice,
        d.PriceCurrency,
        d.AdType,
        d.Rooms,
        d.Restrooms,
        d.Description,
        d.AdStatus
    });

При вызове queryResults.Count() или queryResults.ToArray() это занимает почти 2 минуты.

Модель:

public class Ads
{
    [Key]
    [Index]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int AdsID { get; set; }
    [Index]
    [MaxLength(128)]
    public string Username { get; set; }
    [Index]
    [MaxLength(64)]
    public string country { get; set; }
    [Index]
    [MaxLength(64)]
    public string administrative_area_level_1 { get; set; }
    [Index]
    [MaxLength(64)]
    public string administrative_area_level_2 { get; set; }
    [MaxLength(64)]
    public string administrative_area_level_3 { get; set; }
    [MaxLength(64)]
    public string neighborhood { get; set; }
    [MaxLength(64)]
    public string Address { get; set; }
    // Navigation property
    public virtual ICollection<PictureAds> Pictures { get; set; }
    [MaxLength(256)]
    public string PictureUrl { get; set; }
    [MaxLength(256)]
    public string UserPicUrl { get; set; }
    [Index]
    [DisplayFormat(DataFormatString = "{0:n15}", ApplyFormatInEditMode = true)]
    public decimal Latitude { get; set; }
    [Index]
    [DisplayFormat(DataFormatString = "{0:n15}", ApplyFormatInEditMode = true)]
    public decimal Longitude { get; set; }
    [DataType(DataType.Date)]
    public DateTime CreatedDate { get; set; }
    [DataType(DataType.Date)]
    public DateTime ExpirationDate { get; set; }
    public int MonthsAlive { get; set; }
    public decimal PriceSurfaceRatio { get; set; }
    public bool FeaturedAd { get; set; }
    public bool PremiumAd { get; set; }
    public int Views { get; set; }
    [MaxLength(256)]
    public string Code { get; set; }
    [MaxLength(256)]
    public string Title { get; set; }
    [MaxLength(32)]
    public string SunOrientation { get; set; }
    public bool IsFurnished { get; set; }
    [Required]
    [MaxLength(64)]
    public string Name { get; set; }
    [Required]
    [MaxLength(64)]
    public string Email { get; set; }
    [Required]
    [MaxLength(32)]
    public string Phone { get; set; }
    [Required]
    [MaxLength(32)]
    public string UserType { get; set; }
    [Required]
    [Index]
    [MaxLength(32)]
    public string OperationType { get; set; }
    [Required]
    public int Price { get; set; }
    [Index]
    public int? USDPrice { get; set; }
    [Required]
    [MaxLength(16)]
    public string PriceCurrency { get; set; }
    [Required]
    [Index]
    [MaxLength(32)]
    public string AdType { get; set; }
    [Required]
    public int SizeTotal { get; set; }
    public int SizeIndoor { get; set; }
    public int SizeOutdoor { get; set; }
    public int Expenses { get; set; }
    [Index]
    public int Rooms { get; set; }
    [Index]
    public int Restrooms { get; set; }
    [MaxLength(16)]
    public string Age { get; set; }
    public int Garage { get; set; }
    public string Description { get; set; }
    [Index]
    [MaxLength(32)]
    public string AdStatus { get; set; } //Pending/Approved/Denied/OnHold
}

public class PictureAds
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int PictureAdID { get; set; }
    public string url { get; set; }

    // Foreign key
    public int AdsID { get; set; }

    // Navigation properties
    public virtual Ads AdsModels { get; set; }
}

================================================== ===========

Это обновленный код, использующий предложение Clay Ver Valen:

var queryResults = (from d in ApplicationContext.Ads.AsNoTracking()
                                    where (d.Latitude >= latitude - radio)
                                    && (d.Latitude <= latitude + radio)
                                    && (d.Longitude >= longitude - radio)
                                    && (d.Longitude <= longitude + radio)
                                    && (String.IsNullOrEmpty(operationType) || d.OperationType == operationType)
                                    && (!(priceMax > priceMin && (priceMin > 0 || priceMax > 0)) || (d.USDPrice >= priceMin && d.USDPrice <= priceMax))
                                    && (String.IsNullOrEmpty(adType) || d.AdType == adType)
                                    orderby d.USDPrice ascending
                                    select new
                                    {
                                        d.AdsID,
                                        d.Username,
                                        d.administrative_area_level_1,
                                        d.administrative_area_level_2,
                                        d.administrative_area_level_3,
                                        d.neighborhood,
                                        d.Address,
                                        d.PictureUrl,
                                        d.Latitude,
                                        d.Longitude,
                                        d.ExpirationDate,
                                        d.FeaturedAd,
                                        d.PremiumAd,
                                        d.Views,
                                        d.Code,
                                        d.OperationType,
                                        d.Price,
                                        d.USDPrice,
                                        d.PriceCurrency,
                                        d.AdType,
                                        d.Rooms,
                                        d.Restrooms,
                                        d.Description,
                                        d.AdStatus
                                    });

Индекс с несколькими столбцами:

public class Ads
{
    [Key]
    [Index]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int AdsID { get; set; }
    [Index]
    [MaxLength(128)]
    public string Username { get; set; }
    [Index]
    [MaxLength(64)]
    public string country { get; set; }
    [Index]
    [MaxLength(64)]
    public string administrative_area_level_1 { get; set; }
    [Index]
    [MaxLength(64)]
    public string administrative_area_level_2 { get; set; }
    [MaxLength(64)]
    public string administrative_area_level_3 { get; set; }
    [MaxLength(64)]
    public string neighborhood { get; set; }
    [MaxLength(64)]
    public string Address { get; set; }
    // Navigation property
    public virtual ICollection<PictureAds> Pictures { get; set; }
    [MaxLength(256)]
    public string PictureUrl { get; set; }
    [MaxLength(256)]
    public string UserPicUrl { get; set; }
    [Index("IX_FilterAds", 1)] 
    [DisplayFormat(DataFormatString = "{0:n15}", ApplyFormatInEditMode = true)]
    public decimal Latitude { get; set; }
    [Index("IX_FilterAds", 2)] 
    [DisplayFormat(DataFormatString = "{0:n15}", ApplyFormatInEditMode = true)]
    public decimal Longitude { get; set; }
    [DataType(DataType.Date)]
    public DateTime CreatedDate { get; set; }
    [DataType(DataType.Date)]
    public DateTime ExpirationDate { get; set; }
    public int MonthsAlive { get; set; }
    public decimal PriceSurfaceRatio { get; set; }
    public bool FeaturedAd { get; set; }
    public bool PremiumAd { get; set; }
    public int Views { get; set; }
    [MaxLength(256)]
    public string Code { get; set; }
    [MaxLength(256)]
    public string Title { get; set; }
    [MaxLength(32)]
    public string SunOrientation { get; set; }
    public bool IsFurnished { get; set; }


    [Required]
    [MaxLength(64)]
    public string Name { get; set; }
    [Required]
    [MaxLength(64)]
    public string Email { get; set; }
    [Required]
    [MaxLength(32)]
    public string Phone { get; set; }
    [Required]
    [MaxLength(32)]
    public string UserType { get; set; }
    [Required]
    [Index("IX_FilterAds", 3)] 
    [MaxLength(32)]
    public string OperationType { get; set; }
    [Required]
    public int Price { get; set; }
    [Index]
    [Index("IX_FilterAds", 4)] 
    public int? USDPrice { get; set; }
    [Required]
    [MaxLength(16)]
    public string PriceCurrency { get; set; }
    [Required]
    [Index("IX_FilterAds", 5)] 
    [MaxLength(32)]
    public string AdType { get; set; }
    [Required]
    public int SizeTotal { get; set; }
    public int SizeIndoor { get; set; }
    public int SizeOutdoor { get; set; }
    public int Expenses { get; set; }
    [Index]
    public int Rooms { get; set; }
    [Index]
    public int Restrooms { get; set; }
    [MaxLength(16)]
    public string Age { get; set; }
    public int Garage { get; set; }
    public string Description { get; set; }
    [Index]
    [MaxLength(32)]
    public string AdStatus { get; set; } //Pending/Approved/Denied/OnHold
}

1 ответ

Решение

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

Ознакомьтесь с разделом " Индексы с несколькими столбцами" в MSDN, чтобы узнать подробнее о создании индекса с несколькими столбцами, и при создании своего списка обратите особое внимание на порядок столбцов, чтобы он соответствовал вашему запросу. Вы также можете сгруппировать часть широты вашего SQL вместе.

Другие вопросы по тегам