构建数据库以获得最佳性能

时间:2013-08-27 23:05:30

标签: mysql sql database performance

我正在开发“在线流媒体”项目,我需要一些帮助来构建数据库以获得最佳性能。目前我有一个表格,其中包含播放器的所有相关信息,包括文件,海报图片,post_id等。

+---------------+-------------+------+-----+---------+----------------+
| Field         | Type        | Null | Key | Default | Extra          |
+---------------+-------------+------+-----+---------+----------------+
| id            | int(11)     | NO   | PRI | NULL    | auto_increment |
| post_id       | int(11)     | YES  |     | NULL    |                |
| file          | mediumtext  | NO   |     | NULL    |                |
| thumbs_img    | mediumtext  | YES  |     | NULL    |                |
| thumbs_size   | mediumtext  | YES  |     | NULL    |                |
| thumbs_points | mediumtext  | YES  |     | NULL    |                |
| poster_img    | mediumtext  | YES  |     | NULL    |                |
| type          | int(11)     | NO   |     | NULL    |                |
| uuid          | varchar(40) | YES  |     | NULL    |                |
| season        | int(11)     | YES  |     | NULL    |                |
| episode       | int(11)     | YES  |     | NULL    |                |
| comment       | text        | YES  |     | NULL    |                |
| playlistName  | text        | YES  |     | NULL    |                |
| time          | varchar(40) | YES  |     | NULL    |                |
| mini_poster   | mediumtext  | YES  |     | NULL    |                |
+---------------+-------------+------+-----+---------+----------------+

对于100k记录,查询需要大约0.5秒,并且由于我有更多记录,性能会不断下降。

+----------+------------+----------------------------------------------------------------------+
| Query_ID | Duration   | Query                                                                |
+----------+------------+----------------------------------------------------------------------+
|        1 | 0.04630675 | SELECT * FROM dle_playerFiles where post_id in ('7000') AND type='1' |
+----------+------------+----------------------------------------------------------------------+

解释SELECT * FROM dle_playerFiles其中post_id in('7000')AND type ='1';

+----+-------------+-----------------+------+---------------+------+---------+------+-------+-------------+
| id | select_type | table           | type | possible_keys | key  | key_len | ref  | rows  | Extra       |
+----+-------------+-----------------+------+---------------+------+---------+------+-------+-------------+
|  1 | SIMPLE      | dle_playerFiles | ALL  | NULL          | NULL | NULL    | NULL | 61777 | Using where |
+----+-------------+-----------------+------+---------------+------+---------+------+-------+-------------+

如何改善数据库结构?像youtube这样的大型网站如何构建他们的数据库?

2 个答案:

答案 0 :(得分:2)

通常,当查询时间与行数成正比时,这表示表扫描,这意味着对于像

这样的查询
SELECT * FROM dle_playerFiles where post_id in ('7000') AND type='1'

数据库正在执行,就像在迭代每一行并检查它是否符合条件。

典型的解决方案是索引,它是列(或列集)的值的预先计算列表,以及具有所述值的行列表。

如果在dle_playerFiles上的post_id列上创建索引,那么索引基本上会说

1: <some row pointer>, <some row pointer>, <some row pointer>
2: <some row pointer>, <some row pointer>, <some row pointer>
...
100: <some row pointer>, <some row pointer>, <some row pointer>
...
7000: <some row pointer>, <some row pointer>, <some row pointer>
250000: <some row pointer>, <some row pointer>, <some row pointer>

因此,有了这样的索引,上面的查询只会查看索引的节点7000,并知道哪些行包含它。

然后数据库只需要读取post_id为7000的行,并检查它们的类型是否为1。

这会快得多,因为数据库永远不需要查看每一行来处理查询。索引的成本:

  1. 存储空间 - 这是更多数据,必须存储在某处
  2. 更新时间 - 数据库使索引与表的更改保持同步,这意味着INSERT,UPDATE和DELETE语句将需要更长时间,因为它们需要更新数据。对于小而有效的索引,这种权衡通常是值得的。
  3. 对于您的查询,我建议您在2列上创建索引。使它们成为同一索引的一部分,而不是两个单独的索引:

    create index ix_dle_playerFiles__post_id_type on dle_playerFiles (post_id, type)
    

    高效工作的注意事项:

    1. SELECT *在这里很糟糕。如果要返回每一列,则数据库必须转到表中才能读取列,因为索引仅包含用于过滤的列。如果您确实只需要一列或两列,请在SELECT子句中明确指定它们并将它们添加到索引中。不要为许多列执行此操作,因为它只会使索引膨胀。
    2. 函数和类型转换往往会阻止索引使用。您的SQL包装整数类型post_id并键入引号,以便将它们解释为字符串。数据库可能会觉得无法使用索引,因为它必须转换所有内容。删除引号以获得良好的衡量标准。

答案 1 :(得分:1)

如果我正确阅读了您的持续时间,则运行查询似乎需要0.04630675(秒?),而不是0.5秒。

无论如何,正确的索引可以减少返回查询结果所需的时间。根据您的查询SELECT * FROM dle_playerFiles where post_id in ('7000') AND type='1',建议使用post_idtype的索引。

此外,如果您绝对要求返回所有字段,请使用您需要的字段的单独列引用,而不是*。字段越少,查询返回的速度就越快。

优化查询的另一种方法是确保在主/外键和索引字段中使用可能的最小数据类型 - 尤其。如果bigintint或更好,mediumint仍然可以smallinttinyint,则永远不要使用{{1}}或{{1}}。从来没有永远在PK或FK中使用文本字段,除非你没有其他选择(这是一个DB设计犯罪过于经常IMO,即使是有足够的培训和经验的人知道更好) - 你最好使用最小的精确数字类型。所有这些都对存储大小产生了积极影响。