基于索引的mysql表优化

基于索引的mysql表优化,mysql,optimization,Mysql,Optimization,我想优化我的表以加快查询结果。目前我正在使用MyISAM而不是InnoDB 问题是,第一个邮政编码是5个字符长,不是以字母开头的。所有这些邮政编码开始时,字母是6或7字符长,并在表的中间记录。您认为我的表中的记录应该按A-Z顺序还是按邮政编码长度排列?表顶部列出的字符数较少的记录更适合优化 或者你还有什么建议 表结构: 查询: 记录的顺序可能没有影响。您可以通过简化查询来优化一些内容,通过预先计算值来优化一些内容,通过以所需的最小精度存储数据来优化一些内容 我已经对大约10000个随机生成的邮政

我想优化我的表以加快查询结果。目前我正在使用MyISAM而不是InnoDB

问题是,第一个邮政编码是5个字符长,不是以字母开头的。所有这些邮政编码开始时,字母是6或7字符长,并在表的中间记录。您认为我的表中的记录应该按A-Z顺序还是按邮政编码长度排列?表顶部列出的字符数较少的记录更适合优化

或者你还有什么建议

表结构:

查询:


记录的顺序可能没有影响。您可以通过简化查询来优化一些内容,通过预先计算值来优化一些内容,通过以所需的最小精度存储数据来优化一些内容

我已经对大约10000个随机生成的邮政编码进行了一些测试,我看到上述所有内容和此索引的性能大约提高了25%:

CREATE INDEX postcodes_ndx ON postcodes(postcode, latitude, longitude);
您的结果将取决于每行中还有哪些其他数据,以及平台和其他参数

还要考虑利用MySQL的可能性。否则,您可能会尝试为每个邮政编码存储一个现成的UTM位置,只要您没有覆盖像俄罗斯那样宽的区域,并将第一个表限制为以$postcode为中心的方圆三英里内的值。这将立即将检索到的行减少几个数量级,从而按比例提高查询速度

我从连接开始,而不是从子选择开始:

SELECT
(@rownum := @rownum + 1) AS No,
A.postcode AS Postcode,
A.latitude AS Latitude,
A.longitude AS Longitude,
ACOS(
        SIN(B.latitude * PI() / 180) * SIN(A.latitude * PI() / 180) +
        COS(B.latitude * PI() / 180) * COS(A.latitude * PI() / 180) *
        COS((B.longitude - A.longitude) * PI() / 180)
) * 180 / PI() * 60 * 1.1515
AS Distance
FROM postcodes AS A,
(SELECT * FROM postcodes WHERE postcode = $postcode) AS B,
(SELECT @rownum := 0) AS No
HAVING Distance <= 0.5 /*miles*/
ORDER BY Distance ASC;
最后,您可以删除@rownum计算并将其添加回PHP:

$rownum = 1;
while($tuple = SQLFetchTuple($exec))
{
    $tuple['No'] = $rownum++;
    ... same code as before...
}
修剪第一张桌子 这确实会从空间扩展中受益,但我们可以强制第一组邮政编码在距离第一组不到十分之一度的范围内

当然,除非你在赤道上,否则这两个距离是不一样的——你可以计算出一个纬度和经度的增量,大约相当于两到三英里,以获得一个安全余量

SELECT A.postcode AS Postcode,
   A.latitude AS Latitude,
   A.longitude AS Longitude,
   ACOS(
       sinlat * SIN(A.latitude * PI() / 180) +
       coslat * COS(A.latitude * PI() / 180) * COS((B.longitude - A.longitude) * PI() / 180)
   ) * 3958.57 AS Distance
FROM postcodes AS A,
(SELECT latitude, longitude,
  COS(latitude*PI()/180) AS coslat,
  SIN(latitude*PI()/180) AS sinlat
 FROM postcodes WHERE postcode = $postcode) AS B
WHERE
    ABS(A.latitude  - B.latitude ) < 0.1
AND ABS(A.longitude - B.longitude) < 0.1
HAVING Distance <= 0.5

按距离排序ASC

我建议使用带有索引的物化视图。每当您执行COS或SIN之类的函数时,数据库都必须计算该fresh,因此您的索引将被忽略。您应该创建一个物化视图,我认为在MySQL中,它们只是为您预计算解决方案的视图。一旦该解决方案被计算出来,您就可以为物化视图编制索引,并根据该索引进行查询

显然,在MySQL中实现这一点的方法如下:

Create table computed_view  
  --Complex and lengthy sql here  
create index on foo
create index on bar
create index on baz
然后你会做:

select * from computed_view where foo = ? and bar = ?

或者更简单的解决方案。在插入之前计算距离,这样您的数据库就只是一个数据存储库,应该以这种方式处理它。如果你发现自己在数据库中做数学计算,你就走错了路。将其偏移到PHP或您正在使用的任何语言,然后保留计算值。

ummm。。。你在用三角函数做什么?使用正反方向的目的是什么?为什么要使用它们?计算给定邮政编码的距离。不管怎样,我需要它。根据给定邮政编码的距离,这是两个任意邮政编码之间的距离吗?我的查询是:2.4sc,你的:1.7sc:正如你提到的,我还将小数点25,20改为小数点8,5。1.7s仍然很多。又有多少个邮政编码?我们谈论的区域有多大?大约170万。范围约为0.5英里,返回给定邮政编码的428个邮政编码。试试这个-我只为lulz输入0.1,你最好稍微调整一下。让我知道-添加到答案…索引将被忽略,因为您必须计算每次运行。一般来说,您是对的。在这种情况下,我不同意。保持170万个邮政编码之间的距离需要大约3万亿行。另一方面,由于选择是基于距离的,将其卸载到PHP将意味着我们在选择时没有距离,因此我们必须检索所有170万行以在PHP中搅动它们。这也是不容易做到的。
SELECT A.postcode AS Postcode,
   A.latitude AS Latitude,
   A.longitude AS Longitude,
   ACOS(
       sinlat * SIN(A.latitude * PI() / 180) +
       coslat * COS(A.latitude * PI() / 180) * COS((B.longitude - A.longitude) * PI() / 180)
   ) * 3958.57 AS Distance
FROM postcodes AS A,
(SELECT latitude, longitude,
  COS(latitude*PI()/180) AS coslat,
  SIN(latitude*PI()/180) AS sinlat
 FROM postcodes WHERE postcode = $postcode) AS B
WHERE
    ABS(A.latitude  - B.latitude ) < 0.1
AND ABS(A.longitude - B.longitude) < 0.1
HAVING Distance <= 0.5
Create table computed_view  
  --Complex and lengthy sql here  
create index on foo
create index on bar
create index on baz
select * from computed_view where foo = ? and bar = ?