如何在JOIN查询中更快地进行ORDER BY?我没有尝试过任何工作

Pro*_*irl 20 mysql join sql-order-by query-optimization

我有以下JOIN查询:

SELECT
    table1.*, 
    table2.*
FROM 
    Table1 AS table1 
LEFT JOIN 
    Table2 AS table2 
USING 
    (col1)
LEFT JOIN 
    Table3 as table3 
USING 
    (col1) 
WHERE 
    3963.191 * 
    ACOS(
    (SIN(PI() * $usersLatitude / 180) * SIN(PI() * table3.latitude / 180)) 
    +
    (COS(PI() * $usersLatitude / 180) * COS(PI() * table3.latitude / 180) * COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180))
    ) <= 10 
AND 
    table1.col1 != '1' 
AND 
    table1.col2 LIKE 'A' 
AND 
    (table1.col3 LIKE 'X' OR table1.col3 LIKE 'X-Y') 
AND 
    (table2.col4 = 'Y' OR table2.col5 = 'Y') 


// Data Types of all columns in the query:
// col1: int(11)
// col2: char(1)
// col3: varchar(3)
// col4: char(1)
// col5: char(1)
// col6: int(11)
// latitude: varchar(25)
// longitude: varchar(25)

// All 3 tables (table1, table2, and table3) are `MyISAM`.
Run Code Online (Sandbox Code Playgroud)

它在0.15秒内执行.

但是,如果我只是添加:

ORDER BY 
    table1.col6 DESC 
Run Code Online (Sandbox Code Playgroud)

它执行超过3秒.

查询中的所有列都已编制索引,包括在中table1.col6使用的列ORDER BY.

以下是EXPLAIN EXTENDED WITHOUT 的结果ORDER BY:

id  select_type table   type    possible_keys   key key_len ref rows    filtered    Extra
1   SIMPLE  table1  ALL PRIMARY,col2,col3   NULL    NULL    NULL    140101  72.61   Using where
1   SIMPLE  table2  eq_ref  PRIMARY,col4,col5   PRIMARY 4   table1.col1 1   100 Using where
1   SIMPLE  table3  eq_ref  PRIMARY PRIMARY 4   table1.col1 1   100 Using where
Run Code Online (Sandbox Code Playgroud)

以下是EXPLAIN EXTENDED WITH 的结果ORDER BY:

id  select_type table   type    possible_keys   key key_len ref rows    filtered    Extra
1   SIMPLE  table1  ALL PRIMARY,col2,col3   NULL    NULL    NULL    140101  72.61   Using where; Using filesort
1   SIMPLE  table2  eq_ref  PRIMARY,col4,col5   PRIMARY 4   table1.col1 1   100 Using where
1   SIMPLE  table3  eq_ref  PRIMARY PRIMARY 4   table1.col1 1   100 Using where
Run Code Online (Sandbox Code Playgroud)

奇怪的是,我ORDER BY DESC在这个网站上的其他几个查询中使用它,并且它不会像在这个特定查询中那样减慢速度.这个查询有一些特定的东西会导致它显着减慢ORDER BY.

我也在ANALYZE TABLE所有3张桌子上做过,他们都报道了OK.然后我用LIKE查询替换了查询中的每一个,=它实际上使查询没有ORDER BY0.2秒3秒.换句话说,替换LIKE=使原始查询与添加一样长ORDER BY!考虑到LIKE更多的工作,这怎么可能=呢?也许这就是为什么ORDER BY需要这么长时间的线索?

在这里我做了多少尝试(非常成功):

1)而不是SELECT table1.*, table2.*,我尝试了SELECT table1.col1,它仍然需要3秒钟才能完成.

2)我尝试添加一个综合指数col1,col2,col3,和col6Table1,但它并没有提高执行速度.

3)我尝试了这种解决方案,使查询成为一个子查询,然后将其ORDER BY外部包装在最后,但它并没有提高执行速度.

4)我尝试了以下版本的查询,但它没有改进任何东西,实际上使查询花了3秒甚至没有ORDER BY添加到它(也许这提供了另一条线索):

SELECT STRAIGHT_JOIN
      T1.*, 
      T2.*
   FROM 
      Table1 AS T1
         JOIN Table2 AS T2
            ON T1.Col1 = T2.Col1
            AND ( T2.Col4 = 'Y' OR T2.Col5 = 'Y' )
         JOIN Table3 as T3
            ON T1.Col1 = T3.Col1
            AND 3963.191 
               * ACOS(  (SIN(PI() * $usersLatitude / 180) * SIN(PI() * T3.latitude / 180)) 
                                + (  COS(PI() * $usersLatitude / 180) * COS(PI() * T3.latitude / 180) 
                                   * COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180)
                        )   
                     ) <= 10 
   WHERE
          T1.Col2 LIKE 'A'
      AND ( T1.col3 LIKE 'X' OR T1.col3 LIKE 'X-Y') 
      AND T1.Col1 != '1'
   ORDER BY
      T1.Col6

// With the following composite indexes:
// On Table 1, index on ( Col2, Col3, Col1, Col6 )
// On Table 2, index on ( Col1, Col4, Col5 )

// Remember, all individual columns are already indexed.
Run Code Online (Sandbox Code Playgroud)

...

如何让这个顽固的查询快速运行ORDER BY 或者这是不可能的?


编辑:

SHOW CREATE TABLE所有3个表的结果:

CREATE TABLE `Table1` (
 `col1` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `col100` varchar(25) CHARACTER SET utf8 DEFAULT NULL,
 `col101` varchar(60) COLLATE utf8_bin DEFAULT NULL,
 `col102` varchar(50) CHARACTER SET utf8 DEFAULT NULL,
 `col103` varchar(10) COLLATE utf8_bin DEFAULT '00000000',
 `col104` date NOT NULL,
 `col105` int(3) DEFAULT NULL,
 `col106` varchar(25) COLLATE utf8_bin DEFAULT NULL,
 `col107` varchar(20) COLLATE utf8_bin DEFAULT 'Blah',
 `col108` varchar(2) COLLATE utf8_bin DEFAULT 'No',
 `col109` varchar(15) COLLATE utf8_bin DEFAULT 'Blah',
 `col2` enum('A','B') COLLATE utf8_bin DEFAULT NULL,
 `col3` enum('A','B','A-B') COLLATE utf8_bin DEFAULT NULL,
 `col110` decimal(10,7) NOT NULL DEFAULT '0.0000000',
 `col111` decimal(10,7) NOT NULL DEFAULT '0.0000000',
 `col112` char(1) COLLATE utf8_bin DEFAULT 'N',
 `col113` char(1) COLLATE utf8_bin DEFAULT 'N',
 `col114` int(11) DEFAULT NULL,
 `col115` varchar(15) COLLATE utf8_bin DEFAULT 'Blah',
 `col6` int(11) DEFAULT NULL,
 `col117` varchar(45) COLLATE utf8_bin DEFAULT NULL,
 `col118` varchar(2) COLLATE utf8_bin NOT NULL,
 `col119` tinyint(2) NOT NULL,
 `col120` int(6) NOT NULL,
 `col121` varchar(7) COLLATE utf8_bin NOT NULL,
 `col122` varchar(6) COLLATE utf8_bin NOT NULL,
 `col123` char(1) COLLATE utf8_bin NOT NULL DEFAULT 'A',
 `col124` varchar(200) COLLATE utf8_bin NOT NULL,
 `col125` tinyint(4) NOT NULL,
 `col126` tinyint(1) NOT NULL,
 `col127` varchar(1) COLLATE utf8_bin NOT NULL DEFAULT 'A',
 `col128` tinyint(1) NOT NULL DEFAULT '0',
 `col129` smallint(5) unsigned NOT NULL,
 `col130` varchar(1) COLLATE utf8_bin NOT NULL DEFAULT 'A',
 `col131` int(11) NOT NULL,
 `col132` tinyint(1) NOT NULL,
 `col133` tinyint(1) NOT NULL,
 `col134` varchar(1) COLLATE utf8_bin NOT NULL,
 `col135` varchar(200) COLLATE utf8_bin NOT NULL,
 `col136` int(11) NOT NULL,
 `col137` int(10) unsigned NOT NULL,
 `col138` int(11) NOT NULL,
 `col139` tinyint(1) NOT NULL,
 `col140` tinyint(1) NOT NULL,
 `col141` tinyint(4) NOT NULL,
 `col142` varchar(25) COLLATE utf8_bin NOT NULL,
 `col143` varchar(25) COLLATE utf8_bin NOT NULL,
 `col144` tinyint(1) unsigned NOT NULL,
 `col145` tinyint(4) NOT NULL,
 PRIMARY KEY (`col1`),
 KEY `col2` (`col2`),
 KEY `col3` (`col3`),
 KEY `CompositeIndex0` (`col1`,`col2`,`col3`,`col6`),
 KEY `CompositeIndex1` (`col2`,`col3`,`col1`,`col6`),
 KEY `idx01` (`col1`,`col2`,`col3`)
 [19 other indexes that do not involve col1, col2, col3, or col6...]
) ENGINE=MyISAM AUTO_INCREMENT=160640 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

//*******************************************************//

CREATE TABLE `Table2` (
 `col1` int(11) unsigned NOT NULL DEFAULT '0',
 `col201` varchar(45) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT 'Blah',
 `col202` varchar(45) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT 'Blah',
 `col203` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col204` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col205` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col206` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col207` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col208` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col209` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col210` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col211` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col212` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col213` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col214` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col215` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col216` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col217` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col218` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col219` varchar(45) COLLATE utf8_bin DEFAULT 'Blah',
 `col220` varchar(255) COLLATE utf8_bin DEFAULT 'Blah',
 `col221` varchar(255) COLLATE utf8_bin DEFAULT 'Blah',
 `col222` varchar(255) COLLATE utf8_bin DEFAULT 'Blah',
 `col223` varchar(255) COLLATE utf8_bin DEFAULT 'Blah',
 `col224` varchar(45) COLLATE utf8_bin DEFAULT ‘Blah’,
 `col225` varchar(255) COLLATE utf8_bin DEFAULT NULL,
 `col4` char(1) COLLATE utf8_bin DEFAULT 'A',
 `col226` char(1) COLLATE utf8_bin DEFAULT 'A',
 `col227` varchar(5) COLLATE utf8_bin DEFAULT 'Blah',
 `col228` char(1) COLLATE utf8_bin NOT NULL,
 `col229` text COLLATE utf8_bin,
 `col5` char(1) COLLATE utf8_bin DEFAULT 'A',
 `col230` varchar(255) COLLATE utf8_bin DEFAULT 'Blah',
 `col231` varchar(255) COLLATE utf8_bin DEFAULT NULL,
 `col232` varchar(255) COLLATE utf8_bin DEFAULT NULL,
 `col233` varchar(255) COLLATE utf8_bin DEFAULT NULL,
 PRIMARY KEY (`col1`),
 KEY `col4` (`col4`),
 KEY `col5` (`col5`),
 KEY `CompositeIndex1` (`col1`,`col4`,`col5`),
 [4 other indexes not involving col1, col4, col5...]
 FULLTEXT KEY `col220` (`col220`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin

//*******************************************************//

CREATE TABLE `Table3` (
 `col1` int(11) unsigned NOT NULL DEFAULT '0',
 `col300` varchar(255) COLLATE utf8_bin DEFAULT NULL,
 `latitude` varchar(25) COLLATE utf8_bin NOT NULL DEFAULT '0',
 `longitude` varchar(25) COLLATE utf8_bin NOT NULL DEFAULT '0',
 `col301` int(11) DEFAULT NULL,
 `static2` float(18,16) DEFAULT '0.0000000000000000',
 `static3` float(18,16) DEFAULT '0.0000000000000000',
 PRIMARY KEY (`col1`),
 KEY `latitude` (`latitude`),
 KEY `longitude` (`longitude`),
 KEY `static2` (`static2`),
 KEY `static3` (`static3`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin
Run Code Online (Sandbox Code Playgroud)

编辑2:

下面是我的MySQL配置文件.除其他外,请注意如何sort-buffer-size设置1M.根据这个,它不应该设置在上面,256K或者它实际上可以减慢"37x". 这可能是问题的一部分吗?

# The MySQL database server configuration file.

[mysqld]

open-files-limit                = 20000

thread-cache-size               = 16
table-open-cache                = 2048
table-definition-cache          = 512

query-cache-type                = 1
query-cache-size                = 32M
query-cache-limit               = 1M

sort-buffer-size                = 1M
read-buffer-size                = 1M
read-rnd-buffer-size            = 8M
join-buffer-size                = 1M

tmp-table-size                  = 64M 
max-heap-table-size             = 64M

back-log                        = 100
max-connections                 = 200
max-connect-errors              = 10000
max-allowed-packet              = 16M
interactive-timeout             = 600
wait-timeout                    = 180
net_read_timeout        = 30
net_write_timeout       = 30

back_log            = 128

myisam-sort-buffer-size         = 128M

innodb-buffer-pool-size         = 320M
innodb-log-buffer-size          = 4M

innodb-log-file-size           = 128M
innodb-log-files-in-group      = 2

innodb-file-per-table           = 1

[mysqldump]
max-allowed-packet      = 16M
Run Code Online (Sandbox Code Playgroud)

另一方面,以下是EXPLAIN EXTENDEDIVAN最新查询的结果:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  T1  ref PRIMARY,col2,col3,col1,CompositeIndex1,idx01    CompositeIndex1 2   const   92333   Using where; Using filesort
1   SIMPLE  T3  eq_ref  PRIMARY PRIMARY 4   T1.col1 1   Using where
1   SIMPLE  T2  eq_ref  PRIMARY,CompositeIndex1,idx_static1 PRIMARY 4   T1.col1 1   Using where
Run Code Online (Sandbox Code Playgroud)

另一方面,这里有一些非常奇怪的事情.以下版本的查询WITH ORDER BY仅在0.2秒内完成:

SELECT STRAIGHT_JOIN T1 . * , T2 . * 
FROM Table3 AS T3
JOIN Table2 AS T2 ON T3.col1 = T2.col1
AND (
T2.col4 = 'Y'
OR T2.col5 = 'Y'
)
JOIN Table1 AS T1 ON T3.col1 = T1.col1
AND 3963.191 * ACOS( (
SIN( PI( ) * - 87.8819594 /180 ) * SIN( PI( ) * T3.latitude /180 ) ) + ( COS( PI( ) * - 87.8819594 /180 ) * COS( PI( ) * T3.latitude /180 ) * COS( PI( ) * T3.longitude /180 - PI( )* 37.1092162 /180 ) )
) <=10
WHERE T1.col2 LIKE 'A'
AND (
T1.col3 LIKE 'X'
OR T1.col3 LIKE 'X-Y'
)
AND T1.col1 != '1'
ORDER BY T1.col6 DESC
Run Code Online (Sandbox Code Playgroud)

基本上,此版本的查询执行a FROM Table3 AS T3JOIN表1和2,而原始查询执行FROM Table1 AS T1JOIN表2和3.

这是EXPLAIN EXTENDED上面的查询:

id  select_type table   type    possible_keys   key key_len ref rows    filtered    Extra
1   SIMPLE  T3  ALL PRIMARY NULL    NULL    NULL    141923  100 Using where; Using temporary; Using filesort
1   SIMPLE  T2  eq_ref  PRIMARY,col4,col5,CompositeIndex1   PRIMARY 4   T3.col1 1   100 Using where
1   SIMPLE  T1  eq_ref  PRIMARY,col2,col3,col1,CompositeIndex1,idx01    PRIMARY 4   T2.col1 1   100 Using where
Run Code Online (Sandbox Code Playgroud)

注意这个查询实际上对Ivan的原始查询和新查询实际上只做了a filesort和a temporary对比a filesort. 怎么能快10倍?

更奇怪的是,切换顺序JOIN似乎并没有改善原始查询和Ivan的新查询. 这是为什么?

Iva*_*oni 5

好吧,我建议你查询一些重做:

  1. 放入条件不加入相关的地方,请参阅第二个查询:

    AND(T1.col3喜欢'X'或T1.col3喜欢'X-Y')

  2. 避免使用IN

  3. 避免使用=

    AND T1.col3 IN('X','X-Y')

  4. 避免计算在哪里

创建一些新的存储列:

SIN(PI() * T3.latitude / 180)
COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180)
COS(PI() * T3.latitude / 180) 
Run Code Online (Sandbox Code Playgroud)
  1. 预评估

    SIN(PI()*$ usersLatitude/180)COS(PI()*$ usersLatitude/180)

  2. 如果所有这些"技巧"都无法避免文件排序强制索引

mysql查询索引提示

进一步补充

为了删除:

( T2.Col4 = 'Y' OR T2.Col5 = 'Y' )
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您不能使用IN,因此请创建一个新列,该列是此表达式的结果.

alter table table2 add static1 bit default 0;
alter table add index idx_static1(static1);
update table2 t2 set static1=1 where ( T2.Col4 = 'Y' OR T2.Col5 = 'Y' );

alter table table3 add static2 float(18,16) default 0;
update table3 set static2=SIN(PI() * T3.latitude / 180) where 1

alter table table3 add static3 float(18,16) default 0;
update table3 set static3 = COS(PI() * T3.latitude / 180) * COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180)   where 1
Run Code Online (Sandbox Code Playgroud)

如果table1.col2的值很少

alter table table1 change col2 col2 enum('A','B','C');
Run Code Online (Sandbox Code Playgroud)

如果table1.col3的值很少

alter table table1 change col3 col3 enum('X','Y','X-Y');
Run Code Online (Sandbox Code Playgroud)

为alter table add index idx01(col1,col2,col3)所涉及的所有列创建唯一索引

SELECT STRAIGHT_JOIN
      T1.*, 
      T2.*
   FROM 
      Table1 AS T1
         JOIN Table2 AS T2 ON T1.Col1 = T2.Col1
         JOIN Table3 as T3 ON T1.Col1 = T3.Col1

   WHERE static1=1 AND
          T1.Col2 = 'A'
      AND T1.col3 IN ( 'X', 'X-Y') 
      AND T1.Col1 != 1
      AND ACOS(  
                 ( 
                   $usersLatitude_sin_pi_fract180  * t3.static2 
                   + $usersLatitude_cos_pi_fract180  * t3.static3 
                 )   
               ) <= 0,00252321929476 -- this's 10/3963.191
      ORDER BY T1.Col6
Run Code Online (Sandbox Code Playgroud)

您的评论建议我在查询中有不同的排序规则(col1是latin1_swedish,col2是utf8)或者您的连接使用不同的排序规则(您的连接是utf-8并且您查询latin1_german列)所以当您查询时:

t1.col2 = 'A'
Run Code Online (Sandbox Code Playgroud)

Mysql必须将每个值从utf-8转换为latin1.

另请参阅mysql文档的collat​​e部分.

一种快速的方法是将所有(列,表,服务器,连接,客户端)转换为相同的排序规则,如果不需要utf-8,则singel字节会更好.

请注意我的类型错误或语法错误.

进一步补充2

我在测试数据库上重新创建了表,并修复了这些列:t1.col2,t2.col3 必须不可为空,t1.col1是主要的,不能为空.

索引"t1.CompositeIndex1"应仅索引:col2,col3,col1; 索引"order by"列是无用的或最差的.

我创建了static1,我在t2.col1和t2.static1上创建了一个索引,但我没有使用DB中的6行(请参阅后面的解释).t2.static1也不能为空.

我还将查询调整为列的整理:

SELECT  T1.*, T2.* 
FROM Table1 AS T1
         JOIN Table2 AS T2   ON ( T1.Col1 = T2.Col1   )
         JOIN Table3 as T3 ON T1.Col1 = T3.Col1
   WHERE  
         (  T1.Col2 =    'A'   collate utf8_bin  AND T1.col3 IN  ( 'X' collate utf8_bin , 'X-Y'  collate utf8_bin )   AND T1.Col1 != 1 )
and T2.static1=1
      AND ACOS(  (   2.3  * T3.static2  + 1.2 * T3.static3  ) ) <= 0.00252321929476 
      ORDER BY T1.Col6
Run Code Online (Sandbox Code Playgroud)

以下是扩展的解释

+----+-------------+-------+--------+-----------------------------------+-----------------+---------+----------------+------+----------+-----------------------------+
| id | select_type | table | type   | possible_keys                     | key             | key_len | ref            | rows | filtered | Extra                       |
+----+-------------+-------+--------+-----------------------------------+-----------------+---------+----------------+------+----------+-----------------------------+
|  1 | SIMPLE      | T1    | ref    | PRIMARY,col2,col3,CompositeIndex1 | CompositeIndex1 | 1       | const          |    1 |   100.00 | Using where; Using filesort |
|  1 | SIMPLE      | T2    | eq_ref | PRIMARY,CompositeIndex1           | PRIMARY         | 4       | testdb.T1.col1 |    1 |   100.00 | Using where                 |
|  1 | SIMPLE      | T3    | eq_ref | PRIMARY                           | PRIMARY         | 4       | testdb.T1.col1 |    1 |   100.00 | Using where                 |
+----+-------------+-------+--------+-----------------------------------+-----------------+---------+----------------+------+----------+-----------------------------+ 
Run Code Online (Sandbox Code Playgroud)

对于colums 是否相同:select_type,table,type,key,ref,filtered,Extra?

我的优化目标是: - 适应少数索引中的where条件 - 避免计算 - 避免整理转换 - 避免OR - 避免在条件中的NULL

现在坏消息似乎在表中你有~140K记录,并且查询使用顺序可能意味着使用filesort方法如果查询涉及很多行,那么最终答案可以增加memsort缓冲区作为建议通过@mavroprovato.

进一步添加3

为了evauate的充分性的key_buffer_size上看到http://dba.stackexchange.com

进一步补充4

我认为只有甲骨文中的某个人才能确切地说出会发生什么,但我有我的想法.

我认为这个查询很奇怪:

  1. 所有表(t1,t2,t3)都由主键连接
  2. 其他条件仅取决于计算(t3.colX)
  3. 某些条件仅取决于索引(t1.colX)

因为1 from_table_rows> = join1_table_rows> = join2_table_rows,所以较少的行返回from table最快将是其他2个JOIN

评估工作量的优化器将计算出类似的等式:

effort = num_rows*key_size/index_cardinality
Run Code Online (Sandbox Code Playgroud)

(index_cardinality由phpmyadmin显示下一个索引)

因为2次努力是> = num_rows

我的查询 因为3的table1(从表中)返回92333行,table3(join1_table)减少到1(!)行,table2保持1行(努力~3).

您的查询 因为2你应该有一个努力= 140000,但幸运的是你的calc只返回1个结果所以你的查询非常快

笔画演示

在您的查询从"<= 10"(在连接条件中)更改为"<= 1000"或更多时,您将看到性能呈指数下降.

在我的查询中,从"<= 10"(在连接条件下)变为"<= 1000"或更多,您将看到性能的线性/对数减少.

进一步添加5

回答这个问题:sort-buffer-size是不是太大了?

站在文章上,是的,尝试一些调,可能是你可以解决问题

回答问题:不可能快速查询?

恕我直言,这是可能的(即使sort-buffer-size不能解决).

我的想法很简单,它可以在这个动词中恢复:"cirlce很好,但是方形更好".

目前最大的基数在表3中的坐标上,但由于公式没有索引适用.因此,不是搜索半径内的所有点,而是搜索"正方形"内的所有点

FROM table3
...
WHERE (t3.latitude-0.15) < $usersLatitude AND  $usersLatitude < t3.latitude+0.15  
AND t3.longitue - 0.15 < $usersLongitude AND   $usersLongitude < t3.longitue + 0.15
Run Code Online (Sandbox Code Playgroud)

所以你可以在(t3.latitude,t3.longitue)中创建一个索引.

0.15度应该是10英里.当然,您应该在日变化的子午线附近和极点附近修复计算

如果您需要严格的半径,您可以使用半径公式重新连接table3(请参见下面的示例),或者如果可能,执行(/详细说明)公式,直到您可以直接比较值与列.

FROM table3 t3
JOIN table3 t3bis ON t3.id=t3bis.id
...
WHERE (t3.latitude-0.15) < $usersLatitude AND  $usersLatitude < t3.latitude+0.15  
AND t3.longitue - 0.15 < $usersLongitude AND   $usersLongitude < t3.longitue + 0.15
AND 
3963.191 
* ACOS(  (SIN(PI() * $usersLatitude / 180) * SIN(PI() * t3bis.latitude / 180)) 
+ (  COS(PI() * $usersLatitude / 180) * COS(PI() * t3bis.latitude / 180) 
* COS(PI() * t3bis.longitude / 180 - PI() * 37.1092162 / 180)
)   
) <= 10 
Run Code Online (Sandbox Code Playgroud)

进一步补充6

话题:编译好的函数做得更好

使用RADIANS()函数

degree * PI / 180 == radians(degree)
Run Code Online (Sandbox Code Playgroud)

使用mysql的GIS扩展

请参阅有关MySql GIS扩展的文章


Pro*_*irl 0

经过多次尝试和错误,我终于找到了我的问题的解决方案。

如果我们将整个 WHERE 子句(计算半径的部分除外)放在原始查询之外,那么我们会得到一个非常快的查询,它不会temporary像更改执行顺序那样使用JOIN

SELECT * FROM
{
    SELECT
        col1, col2, col3, col4, col5, col6
    FROM 
        Table1 AS table1 
    LEFT JOIN 
        Table2 AS table2 
    USING 
        (col1)
    LEFT JOIN 
        Table3 as table3 
    USING 
        (col1) 
    WHERE 
        3963.191 * 
        ACOS(
        (SIN(PI() * $usersLatitude / 180) * SIN(PI() * table3.latitude / 180)) 
        +
        (COS(PI() * $usersLatitude / 180) * COS(PI() * table3.latitude / 180) * COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180))
        ) <= 10 
) AS sub
WHERE
    col1 != '1' 
AND 
    col2 LIKE 'A' 
AND 
    (col3 LIKE 'X' OR col3 LIKE 'X-Y') 
AND 
    (col4 = 'Y' OR col5 = 'Y') 
ORDER BY 
    col6 DESC 
Run Code Online (Sandbox Code Playgroud)

本质上,这个查询首先JOIN根据半径获取所有 3 个表的结果,然后才应用其余的过滤器来获取我们需要的结果。此版本的查询返回与原始查询完全相同的结果,但执行时间仅为0.2,而原始查询的执行时间超过3 秒。

这是EXPLAIN EXTENDED它的:

id  select_type table   type    possible_keys   key key_len ref rows    filtered    Extra
1   PRIMARY <derived2>  ALL NULL    NULL    NULL    NULL    43  100 Using where; Using filesort
2   DERIVED T3  ALL PRIMARY NULL    NULL    NULL    143153  100 Using where
2   DERIVED users   eq_ref  PRIMARY,col1,idx01  PRIMARY 4   T3.col1 1   100 
2   DERIVED userProfile eq_ref  PRIMARY,CompositeIndex1 PRIMARY 4   users.col1  1   100 
Run Code Online (Sandbox Code Playgroud)

我要感谢Ivan Buttinoni在这方面所做的出色工作。他发现了几种巧妙的方法可以使查询更快。

这个故事的寓意: 不仅可以通过将子句放在主查询之外ORDER BY来加快查询速度,还可以通过将部分 WHERE 子句放在主查询之外来获得更快的查询,在这种情况下也是如此。