mysql - MySQL 中按 DESC、BETWEEN 和几个可能的查询字段集排序的索引

标签 mysql optimization indexing range between

我目前正在构建一个约会网站,因此主要的性能瓶颈预计来自于获取用户配置文件(并且很少添加新的配置文件 - 因此我们读取的次数多于写入的次数)。

目前,我有两个表

1) 用户 - (id, user_name,email,password)

2) person - (id, sex, age, sexual_oreintationm, user_registration_date, user_last_activity 等等 - 相当多的字段)

两者通过ID连接(两张表的编号相同,有约束条件)

(我将 user_registration_date, user_last_activity 字段放在 person 表中,以便不使用 join)

这是检索数据的一般查询(但字段可能会有所不同)

select * from
(SELECT person.id
FROM person
left join site_users on person.id=site_users.id
where
sex =1
and sexual_orientation =1
and relationship =1
and employment = 1
and smoke = 1
and alcohol =1
and sport = 1
and health = 1
and virus_hiv =1
and virus_hepatitis_c = 1
and (height BETWEEN 110 and 180)
and (weight BETWEEN 50 and 250)
and education > 1
order by site_users.user_registration_date
Limit 50 offset 0) as t
join person on  t.id=person.id
join site_users on t.id = site_users.id;

与复合索引相关的所有问题

1) MYSQL 是否可以在使用索引的同时使用多个BETWEEN 条件? (在测试中我得出的结论是 - MSYQL 只能使用第一个 BETWEEN 条件,如果它包含在索引中的顺序与 SELECT QUERY 中的条件顺序相对应).

2) MYSQL 是否使用索引进行ORDER BY DESC(例如user_registation_date)?我需要将 user_registation_date 文件放在复合索引中的什么确切位置才能使其正常工作?

3) 是否需要将ID归档到复合索引中?具体在什么地方? (我的意思是在最好的情况下——它会导致 MYSQL 根本不必读取真实的表,而只从索引中读取数据吗?)

4) 如何为不同的字段集创建复合索引?

例如- 使用要过滤 (sex = 1, orientation =2) 或 (height > 180 and weight < 100) 我是否需要创建所有可能的索引组合? (听起来很疯狂)

5) 我怎样才能进一步优化我的查询? (我需要使用 order by,limit 和 offset 来分页)

最佳答案

阅读https://use-the-index-luke.com

1) Is it possible in MYSQL to use several BETWEEN conditions while using indexes for it?

简单的答案是否定的,查询计划器只能对多列索引的第一列进行范围扫描。

更复杂的答案是做这样的事情

SELECT id, whatever
FROM tbl
WHERE col1 BETWEEN val AND val
  AND id IN (SELECT id FROM whatever WHERE col2 BETWEEN x AND y)

每个子查询可以使用不同的索引。这不是非常有效,但比全表扫描要好。

(... I have concluded that - MySQL can use only the first BETWEEN condition and if it is included in the index in the order that corresponds to order of conditions in SELECT query)

正确。

2) Does MySQL use indexes for ORDER BY DESC

是的。在 MySQL 8 中,开发人员添加了 descending indexes ,这有助于提高 ORDER BY ... DESC 的效率。但无论如何它都可以使用索引。 (例如 user_registation_date)?我需要将 user_registation_date 文件放在复合索引中的什么确切位置才能使其正常工作?

3) Do I need to put the ID filed in the compound index?

在 InnoDB 表中,pk 是每个索引的隐式部分。所以,在 InnoDB 中,没有。在 MyISAM 中,是的。

(... in the best case scenario - will it lead to MYSQL not having to read the real table at all, only reading data from Indexes?)

如果将满足查询所需的所有列都放在索引中,查询计划器就不需要读取真实的表。这称为复合覆盖索引。

4) How do I create compound indexes for different sets of fields?

如果您有多种搜索条件组合,并且必须使用索引来搜索它们,则需要适当组合的索引。这确实会让您认为您需要大量的索引。但请记住,您可以使用索引来缩小搜索范围,然后逐行扫描较少的行以完成其余的过滤。如果您索引具有高选择性的列,这有助于提高性能,但并不完美。

什么色谱柱选择性高?出生日期可能会,因为其中有广泛的值分布。性别通常不会,因为大多数值具有两个值之一。

您总是可以在发现需要时添加索引。随着数据库在生产中的增长,通常会根据经验添加(和删除)索引。

e.g. - users want to filter ( sex = 1, orientation =2) or (height > 180 and weight < 100)

OR 是一个特例,因为 OR 子句的两边都不能用来缩小搜索范围。对于这些,您可能希望使用上面提到的 WHERE id IN(子查询) 模式。

5) How can I possible further optimize my query? (I need use order by, limit and offset for pagination)

SELECT lots of stuff ... ORDER BY ... LIMIT ... OFFSET ... 是一个臭名昭著的性能反模式。为什么?查询规划器对大量数据进行排序,然后丢弃大部分数据。您可以尝试延迟加入。这使用子查询来检索相关的 id,然后加入详细信息。像这样:

   SELECT whatever, whatever, whatever ...
     FROM table a
    WHERE id IN (
                  SELECT id  
                    FROM table
                   WHERE filter-criterion
                     AND filter-criterion
                   ORDER BY something DESC, anotherthing
                   LIMIT k OFFSET j
                )
    ORDER BY something DESC, anotherthing

这允许查询规划器使用限制和偏移量对更少的列进行排序,然后检索仅需要的行子集所需的所有列。

Where in an index should a column be placed to support ORDER BY thatcolumn

索引是随机访问的,然后在高效查询中顺序访问。

例如

 SELECT whatever
   FROM table
  WHERE gender='f'
    AND category = 1
    AND dob >= '2001-01-01
    AND dob < '2010-01-01'
  ORDER BY acoount_balance

利用 (category, gender, dob, account_balance) 上的 BTREE(排序)索引,因为它可以随机访问索引到第一个符合条件的条目,然后按顺序扫描到最后一个符合条件的条目。当它扫描每个条目时,它会选择 account_balance 值并使用它进行排序。这基本上涵盖了索引行为。

 SELECT whatever
   FROM table
  WHERE gender='f'
    AND category = 1
    AND dob >= '2001-01-01
    AND dob < '2010-01-01'
  ORDER BY dob

是一个特例。在找到第一个 elibile 索引条目后,MySQL 利用可以满足其 ORDER BY 要求的事实,因为它按顺序扫描索引。

专业提示:在构建用于生产用途的新应用程序时,不要过多考虑这些索引内容。在您的表变大之前,您不需要复杂的索引。当它们确实变大时,您会发现您对正确索引的猜测至少有些错误。在不断增长的真实世界数据库中,标准做法是每隔几周查看一次慢速查询,使用 EXPLAIN 找出 MySQL 如何满足它们,并根据需要添加或删除索引以提高性能您的用户真正关心的案例。

关于mysql - MySQL 中按 DESC、BETWEEN 和几个可能的查询字段集排序的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51536027/

相关文章:

excel - 将多个值索引到单个单元格中

python - 慢速搜索

c# - 从数据库反序列化二进制数组 C#

php - 是否可以创建一个涉及 3 个表和条件语句的触发器?

java - 将新的 Key 添加到 HashMap 的最后一个索引而不是第一个索引

function - 使用 F# 优化记录中的函数值访问

python - 有效地重新排列多维数组的列

python - 下载 CSV 文件,然后使用 Python 上传到 MySQL

python - "MySQL server has gone away"长时间空闲后出现错误

c++ - 在优化阶段内联虚拟方法和静态分析