mysql中order by desc的索引,介于和几个可能的查询字段集之间

q9rjltbz  于 2021-06-20  发布在  Mysql
关注(0)|答案(2)|浏览(472)

我目前正在建立一个交友网站,所以主要的性能瓶颈预计来自获取用户配置文件(而且很少添加新的配置文件-所以我们阅读的频率比写作的频率高)。
目前,我有两张table
1) 用户-( id, user_name,email,password )
2) 人-( 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中,在使用索引的同时,是否可以使用多个中间条件(在测试中,我得出的结论是-msyql只能使用第一个between条件,如果它按照与selectquery中的条件顺序对应的顺序包含在索引中,则可以使用第一个between条件。
2) mysql是否对order by desc使用索引(例如 user_registation_date )? 在复合索引中,我需要把 user_registation_date 为了让它工作?
3) 我需要把身份证放在复合索引里吗?在什么地方(我的意思是在最好的情况下——会不会导致mysql根本不必读取真正的表,只从索引中读取数据?)
4) 如何为不同的字段集创建复合索引?
e、 g.-用户想要筛选(性别=1,方向=2)或(身高>180,体重<100)我需要创建所有可能的索引组合吗(听起来很疯狂)
5) 如何进一步优化查询(我需要使用order by,limit和offset进行分页)

dzhpxtsq

dzhpxtsq1#

(不同意o。琼斯)我严重怀疑这个例子的外部部分是否能够有效地使用两个索引并更快。一旦它到达了外部,它将需要一个综合指数 col1 以及 id ,但它不会超过第一列,因为它是一个“范围”。 WHERE col1 BETWEEN val AND val AND id IN (SELECT id FROM whatever WHERE col2 BETWEEN x AND y) 即使在MySQL8之前,索引也可以用于order by x desc——但是您的复杂查询不太可能通过where to get the order by,无论是asc还是desc,无论是8.0还是更早版本。
我建议你穿上 id 在您希望使用它的任何索引的末尾。这是给读者的一条线索;它对空间或性能没有影响。
“完全从索引中读取”称为“索引扫描”(如果扫描),“使用索引”(如果扫描) EXPLAIN ),或“覆盖指数”(在理论讨论中)。它可能更快,因为它可能有更好的顺序列或索引可能更小。如果表/索引的大小超过了可以缓存在ram中的大小,则后一种情况尤其方便。
使用由测试的字段启动复合索引 = (性,运动,…),然后你有一次机会为一个范围添加另一列。
如果 WHERE 就是这样 = 你从一组列开始索引(在你的应用程序中可能不实用),然后在 ORDER BY 列。然后,优化器可能会避免对 ORDER BY 也许可以停止 LIMIT .
WHERE a=1 AND c=2 (未提及 b ), INDEX(a,b,c) 不会过去的 a . 相反 INDEX(a,c,...) 或者 INDEX(c,a,...) 将是最佳的。
由于您似乎有很多真/假标志,请考虑使用 SET 或者 INT 抱着一堆。索引没有帮助(除非覆盖),但它会显著缩小表的大小。
我将在此处讨论有关创建索引的更多信息:http://mysql.rjweb.org/doc.php/index_cookbook_mysql
只有mysql 8.0可以处理方向的混合优化: ORDER BY x ASC, y DESC . (旧版本通过收集可能的行,排序,然后查看 LIMIT 以及 OFFSET .)
但让我们回到真正的问题上来——您有大量的属性,用户可以指定其中的任何子集。这就导致了不可能优化的局面。因此,我建议将属性的子集(最常用的属性)标识为列。然后把剩下的扔进垃圾桶 JSON mysql未查看的字符串。相反,应用程序会进行第二级过滤。对于“common”列,创建一些2列或3列索引(注意我的 a,b,c 以上示例。)
关于eav的讨论:http://mysql.rjweb.org/doc.php/eav
另一个想法: sex + orientation 可能会变成 ENUM('MF', 'FM', 'MM', 'FF', ...) 哪里 MF 意思是“男找女”。并将此列用作大多数索引中的第一列(好吧,我不知道如何用一种实际的方式来表示“mail looking for either”。它可能涉及 UNION 两个查询。)

pw9qyyiw

pw9qyyiw2#

阅读https://use-the-index-luke.com
1) 在mysql中,在使用索引的同时,是否可以使用多个中间条件?
简单的答案是否定的,查询规划器只能对多列索引的第一列进行范围扫描。
更复杂的答案是这样做

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

每个子查询可以使用不同的索引。这并没有惊人的效率,但它比全表扫描要好。
(... 我得出的结论是-mysql只能使用第一个between条件,如果它以与select查询中的条件顺序对应的顺序包含在索引中)
对的。
2) mysql是否使用order by desc索引
对。在mysql 8中,开发人员添加了降序索引,这很有帮助 ORDER BY ... DESC 提高效率。但它可以在任何情况下使用索引(例如用户(注册日期)?我需要在复合索引中的哪个确切位置放置用户注册日期文件才能使其工作?
3) 我需要把身份证放在复合索引里吗?
在innodb表中,pk隐式地是每个索引的一部分。所以,在innodb,不,在myisam,是的。
(... 在最好的情况下——会不会导致mysql根本不必读取真正的表,只从索引中读取数据?)
如果将满足查询所需的所有列都放在索引中,则查询计划器不需要读取实际表。这叫做复合覆盖指数。
4) 如何为不同的字段集创建复合索引?
如果您有许多搜索条件的组合,并且必须使用索引来搜索它们,则需要以适当的组合使用索引。这确实会让你觉得你需要大量的索引。但请记住,您可以使用索引缩小搜索范围,然后逐个扫描较少的行来执行其余的筛选。如果索引具有高选择性的列,这有助于提高性能,但并不完美。
wnat型色谱柱具有很高的选择性?出生日期可能是这样的,因为它的值分布很广。性别通常没有,因为大多数价值观有两种价值观中的一种。
当您发现需要索引时,可以随时添加索引。随着数据库在生产中的增长,通常会根据经验添加(或删除)索引。
e、 g.-用户希望筛选(性别=1,方向=2)或(身高>180,体重<100) OR 是个特例,因为 OR 子句可用于缩小搜索范围。你可以使用 WHERE id IN (subquery) 上面提到的这些模式。
5) 如何进一步优化查询(我需要使用order by,limit和offset进行分页) 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

这允许查询计划器使用limit和offset对更少的列进行排序,然后检索所需行子集所需的所有列。
在索引中,应将列放置在何处以支持 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

利用上的btree(排序)索引 (category, gender, dob, account_balance) 因为它可以随机访问索引到第一个符合条件的条目,然后按顺序扫描到最后一个符合条件的条目。当它扫描每个条目时,它会选择 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利用了这样一个事实:当它顺序扫描索引时,orderby需求可以得到满足。
专业提示:在构建用于生产的新应用程序时,不要过度考虑这个索引。在表变大之前,不需要复杂的索引。当它们变大时,你会发现你对正确索引的猜测至少有些错误。在不断增长的真实数据库中,标准做法是每隔几周查看一次缓慢的查询,使用 EXPLAIN 找出mysql是如何满足它们的,并根据需要添加或删除索引,以提高用户实际关心的情况下的性能。

相关问题