从设计的角度来看,SELECT FROM LIKE 语句的开销有多大?

Jér*_*nge 3 mysql performance select query-performance

关于需要在大型目录结构中随机访问的小型静态文件的数量不断增加,我遇到了一种情况无法控制。我必须尽快大幅减少这些文件的数量。我正在研究释放压力的快速解决方案。

一种选择是将文件的内容(UTF8 文本)移动到数据库中并执行SELECTs 来替换文件搜索(按名称)。选择语句如下:

SELECT TOP(1) MyContent FROM MyTable WHERE MyContentName LIKE 'criteria%';
SELECT TOP(1) MyContent FROM MyTable WHERE MyContentName LIKE '%othercriteria';
SELECT TOP(1) MyContent FROM MyTable WHERE MyContentName LIKE '%andanothercriteria%';
Run Code Online (Sandbox Code Playgroud)

我们谈论的是每天在 800K 行表上的总共 200K 请求(如果有帮助,我可以轻松地将其拆分为两个)。MyContentName是键的一部分,将被编入索引。要么有一个条目与表中的条件匹配,要么没有。

我不是数据库管理员专家。这是共享服务器上的 MySQL 实例可以支持的东西还是我的期望太高?

我知道典型的答案是:我应该测试。不幸的是,由于紧急情况,我没有时间进行测试。我需要找到一个快速的解决方案,即使是暂时的,即使它会稍微降低服务响应延迟。

我正在寻找有经验的数据库管理员对此策略的意见。也欢迎提示和建议。

Bru*_*eis 6

如果您无法微调文件系统(例如,通过使用较小的块大小),并且您确实必须使用数据库,我建议您阅读以下内容:

第一个将解释索引最常用的数据结构,即 B 树。第二个解释了 MySQL 如何使用 B 树。第三个将告诉您有关命令的信息EXPLAIN SELECT ...,这是 MySQL 描述查询计划的方式(它将告诉您它正在使用哪个(如果有)索引,如果它正在执行表扫描——您必须不惜一切代价避免这样做)。

要创建优化的索引,您应该首先考虑您需要的查询(或多个查询)的结构。例如,它可能类似于:select content from files where firstParameter = XXX and secondParameter like 'xxx%'

您应该分析每一列的基数(即,该列可以有多少个不同的值)。

您选择基数最高的列作为索引中的第一列,将基数较低的列留在最后。示例:假设您有 2M 行,并且firstParameter是 1 到 1M 之间的数字,随机分布,并且secondParameter是文件所有者的全名。在这种情况下,您需要 index (firstParameter, secondParameter),按照这个顺序,因为该子句firstParameter = XXX平均只剩下 2 行。secondParameter另一方面,的基数要低得多:人名的可能性远小于 100 万。因此,如果您的索引是(secondParameter, firstParameter),则查询where firstParameter = 1 and secondParameter like 'bruno%'将首先查找以secondParameter开头的每一行bruno(可能是数万或数十万),然后才会查找其他条件。

另请注意,索引是从左到右使用的。也就是说,如果你有3列,ABC你指数(A, B, C),该指数将在一个查询大多无用如where A = 1 and C = 2。它可能会用于查找匹配的行A = 1,但之后将检查每一行C = 2。如果您的大多数查询都与此类似(有些也可能指定 B),那么您的索引应该是(A, C, B).

最后,注意like 'xxx%'可以使用索引,而like '%xxx'(或like '%xxx%') 不能。这也是因为索引是从左到右读取的。为了匹配xxx%,它知道从哪里开始寻找;要匹配%xxx它必须检查每一行。

说了这么多关于索引,我强烈建议你重新设计你的标准,以便你有一些更有条理的东西。正如你所说,你可以尝试预先计算一些东西。

还有其他考虑因素,例如内容的大小。如果你能把它放在 8KB 以下(如果你使用 UTF-8 相当于 3000 个字符),那么 InnoDB 会将数据存储在与主键相同的页面中;否则,它会将数据存储在别处。如果您按主键查询,在第一种情况下,您只有一个读取操作;如果您通过另一个索引查询,在第二种情况下,您有 3 个读取操作:一个查找匹配行的主键,一个通过主键查找行(读取数据的地址)和一个读取数据.

哦,检查您服务器的 RAM 量。理想情况下,您的数据(或至少您的索引)应该适合 RAM。

通过考虑所有这些点,您应该完全没有问题:我不知道您的服务器的硬件或其负载(因为您说它是共享的),但是如果您微调索引,800k 行几乎为零; 我离专家还很远,通过做上述所有事情,我每天都在处理(非常优化的)10M、100M 行的表,并且查询速度非常快。

我希望这有帮助。一旦你有了你的表,你可以问另一个问题,显示create table语句并描述一些关于你的数据(大小、基数等)和你将使用的选择查询,这样有人可以帮助你创建一个优化的索引。