20

次の 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`.

0.15 秒未満で実行されます。

ただし、単純に追加すると:

ORDER BY 
    table1.col6 DESC 

3 秒以上で実行されます。

で使用されるを含め、クエリ内のすべての列にインデックスが付けられます。 table1.col6ORDER 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

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

奇妙なことに、私はORDER BY DESCこのサイトの他のいくつかのクエリで使用していますが、この特定のクエリほど遅くはありません。このクエリに固有の何かがあり、ORDER BY.

また、ANALYZE TABLE3 つのテーブルすべてで を実行したところ、すべてOK. LIKE次に、クエリ内の every を 0.2 秒から 3 秒に置き換えて、実際にクエリなし作成まし=た。つまり、 で置き換えると、元のクエリに!を追加するのと同じくらい時間がかかります。よりも多くの作業を行うことを考えると、それはどのように可能ですか? おそらくそこに、なぜそんなに時間がかかるのかについての手がかりがありますか?ORDER BYLIKE=ORDER BYLIKE=ORDER BY

これまでに試したことは次のとおりです(失敗しました):

1) の代わりにSELECT table1.*, table2.*、ちょうど試してみましたが、完了するまでに3 秒以上かかりSELECT table1.col1まし

2) 、、、およびに複合インデックスを追加しようとしましたが、実行速度が向上しませんでした。col1col2col3col6Table1

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.

...

この頑固なクエリを高速に実行するにはどうすればよいORDER BYですか? それとも、それは不可能ですか?


編集:

SHOW CREATE TABLE3 つのテーブルすべての結果:

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

編集2:

以下は私のMySQL構成ファイルです。sort-buffer-size特に、が に設定されていることに注意してください1Mthisによると、それより上に設定しないでください。そうしないと、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

EXPLAIN EXTENDED別の問題として、 IVAN からの最新のクエリの結果は次のとおりです。

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

別の問題として、ここに非常に奇妙なことがあります。次のバージョンの WITH クエリは、わずか0.2 秒ORDER BYで完了します。

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

基本的に、このバージョンのクエリはテーブル 1FROM Table3 AS T3JOIN2 を実行しますが、元のクエリはテーブル 2 と 3FROM Table1 AS T1を実行します。JOIN

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

Ivan からの元のクエリと新しいクエリに対して、 このクエリが実際に afilesortと a の両方を実行するのに対して、atemporaryだけを実行する方法に注目してください。どうすれば 10 倍速くなるでしょうか。filesort

さらに奇妙なことに、の順序を切り替えてJOINも、元のクエリも Ivan からの新しいクエリも改善されないようです。 何故ですか?

4

5 に答える 5

5

さて、私はあなたにクエリのいくつかのリスタイルを提案します:

  1. 条件が結合に関連しない場所に配置します。2番目のクエリを参照してください。

    AND(T1.col3 LIKE'X'またはT1.col3LIKE'XY')

  2. INを避けるか使用する

  3. 使用のように避けてください=

    AND T1.col3 IN('X'、'XY')

  4. ここでの計算は避けてください

保存する新しい列をいくつか作成します。

SIN(PI() * T3.latitude / 180)
COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180)
COS(PI() * T3.latitude / 180) 
  1. 事前評価

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

  2. これらすべての「トリック」がファイルソートを回避できない場合は、インデックスを強制的にソートします

mysqlクエリインデックスヒント

さらに追加

削除するには:

( T2.Col4 = 'Y' OR T2.Col5 = 'Y' )

この場合、 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

table1.col2の値が少ない場合

alter table table1 change col2 col2 enum('A','B','C');

table1.col3の値が少ない場合

alter table table1 change col3 col3 enum('X','Y','X-Y');

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

あなたのコメントは、クエリで別の照合を使用している(col1はlatin1_swedish、col2はutf8)か、接続で別の照合を使用している(接続はutf-8で、latin1_german列をクエリしている)ことを示唆しています。

t1.col2 = 'A'

Mysqlは、各値をutf-8からlatin1に変換する必要があります。

mysqlドキュメントのcollat​​eセクションも参照してください。

簡単な方法は、すべて(列、テーブル、サーバー、接続、クライアント)を同じ照合シングルバイトに変換することです。utf-8が必要ない場合は、より適切です。

タイプエラーや構文エラーに注意してください。

さらに2を追加

テストDBでテーブルを再作成し、次の列を修正しました。t1.col2、t2.col3はnull許容ではなく、t1.col1はプライマリであり、nullにすることはできません。

インデックス"t1.CompositeIndex1"は、次のインデックスのみをインデックス付けする必要があります:col2、col3、col1; 「順序付け」列のインデックスは、役に立たないか、最悪です。

static1を作成し、t2.col1とt2.static1にインデックスを作成しましたが、DBの6行は使用されていません(後述の説明を参照)。t2.static1もnull許容であってはなりません。

また、クエリを列の照合に適合させます。

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

ここに拡張された説明が続きます

+----+-------------+-------+--------+-----------------------------------+-----------------+---------+----------------+------+----------+-----------------------------+
| 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                 |
+----+-------------+-------+--------+-----------------------------------+-----------------+---------+----------------+------+----------+-----------------------------+ 

カラムについても同じですか:select_type、table、type、key、ref、filtered、Extra?

私の最適化の目標は次のとおりです。-いくつかのインデックスにwhere条件を適合させる-計算を回避する-照合変換を回避する-ORを回避する-where条件でNULLを回避する

悪いニュースですが、テーブルには最大140Kのレコードがあり、順序を使用したクエリは、クエリに多数の行が含まれる場合にファイルソートアプローチを使用することを意味する可能性があるため、最終的な答えは、提案されているようにmemsortバッファーを増やすことができます。 @mavroprovatoによる。

さらに3を追加

key_buffer_sizeの妥当​​性を評価するには、 http: //dba.stackexchange.comを参照してください。

さらに4を追加

オラクルの誰かだけが何が起こっているのかを正確に言うことができると思いますが、私は自分の考えを持っています。

このクエリは独特だと思います。

  1. すべてのテーブル(t1、t2、t3)は主キーで結合されます
  2. 他の条件はcalcs(t3.colX)のみに依存します
  3. 一部の条件は、インデックス(t1.colX)のみに依存します

1 from_table_rows> = join1_table_rows> = join2_table_rowsであるため、fromテーブルを返す行が少なくなると、他の2つのJOINになります。

努力を評価するためのオプティマイザーは、同様の方程式を計算します。

effort = num_rows*key_size/index_cardinality

(index_cardinalityは、各インデックスの次のphpmyadminによって表示されます)

2つの努力のために>=num_rows

私のクエリ は3であるため、table1(テーブルから)は92333行を返し、table3(join1_table)は1(!)行に減少し、table2は1行を保持します(努力〜3)。

2のためのクエリ は、努力= 140000である必要がありますが、幸いなことに、計算は1つの結果しか返さないため、クエリは非常に高速です。

デモストレーション

クエリを「<=10」(結合条件)から「<= 1000」以上に変更すると、パフォーマンスが指数関数的に低下します。

「<=10」(結合条件)から「<= 1000」以上に変更するクエリでは、パフォーマンスの線形/対数の低下が見られます。

さらに5を追加

質問への回答:sort-buffer-sizeが大きすぎますか?

記事の上に立って、はい、いくつかの曲を試してみてください、あなたは問題を解決できるかもしれません

質問への答え:簡単なクエリを実行することは不可能ですか?

私見いいえ、それは可能です(sort-buffer-sizeが解決しない場合でも)。

私の考えは非常に単純で、「cirlceはいいですが、squareの方が良い」というモットーで再開できます。

現時点で最大のカーディナリティは表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

したがって、(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 

さらに6を追加

トピック:コンパイルされた関数はそれをより良くします

RADIANS()関数の使用

degree * PI / 180 == radians(degree)

mysqlのGIS拡張の使用

MySqlGIS拡張機能に関するこの記事を参照してください

于 2012-11-26T17:54:56.910 に答える
0

私があなたにできると思うことは3つあります:

1)クエリをリファクタリングする

2)クエリの前半で表1にORDERBYを適用します

3)リファクタリングをサポートするためのインデックスTable1

おそらくこれ...

ALTER TABLE Table1 ADD INDEX col2_col6_ndx (col2,col6);
SELECT
    table1.*, 
    table2.*
FROM 
    (
        SELECT * FROM Table1
        WHERE col2='A' AND 
        ORDER BY col6 DESC
    ) AS table1
LEFT JOIN 
    (
        SELECT * FROM Table2
        WHERE (col4='Y' OR col5='Y')
    ) AS table2 
USING 
    (col1)
LEFT JOIN 
    Table3 as table3 
USING 
    (col1) 
WHERE 
    table1.col1 != '1' AND
    table1.col3 IN ('X','X-Y') AND
    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 
;

これは、クエリをリファクタリングして、最初にキーのみが収集され(はるかに小さい一時テーブルが作成され)、次にJOINSが適用されるようにする別のバリ​​エーションです。

ALTER TABLE Table1 ADD INDEX col2613_ndx (col2,col6,col1,col3);
ALTER TABLE Table2 ADD INDEX col4_col1_ndx (col4,col1);
ALTER TABLE Table2 ADD INDEX col5_col1_ndx (col5,col1);
SELECT 
    table1.*, 
    table2.*
FROM
(
    SELECT table1.col1,table3.latitude,table3.longitude 
    FROM 
        (
            SELECT col1 FROM Table1 WHERE col2='A' AND
            AND col3 IN ('X','X-Y') ORDER BY col6 DESC
        ) AS table1
    LEFT JOIN 
        (
            SELECT col1 FROM Table2 WHERE col4='Y' UNION
            SELECT col1 FROM Table2 WHERE col5='Y'
        ) AS table2 
    USING (col1)
    LEFT JOIN Table3 as table3 USING (col1)
) col1_keys
LEFT JOIN Table1 table1 USING (col1)
LEFT JOIN Table2 table2 USING (col1)
WHERE 
    3963.191 * 
    ACOS(
    (SIN(PI() * $usersLatitude / 180) * SIN(PI() * col1_keys.latitude / 180)) 
    +
    (COS(PI() * $usersLatitude / 180) * COS(PI() * col1_keys.latitude / 180)
    * COS(PI() * col1_keys.longitude / 180 - PI() * 37.1092162 / 180))
    ) <= 10 
;

試してみる !!!

于 2012-12-07T09:29:34.720 に答える
0

多くの試行錯誤の後、私はついに私の質問に対する解決策を見つけました。

WHERE 句全体(半径を計算する部分を除く) を元のクエリの外側に配置すると、do の順序を変更するなどを使用しない非常に高速なクエリが得られます。temporaryJOIN

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 

基本的に、このクエリは最初にJOIN半径に基づいて 3 つのテーブルすべての結果を取得し、次に残りのフィルターを適用して必要な結果を取得します。このバージョンのクエリは、元のクエリとまったく同じ結果を返しますが、元のクエリでは3 秒以上かかるのに対し、わずか0.2 秒で実行されます。

これがその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 

Ivan Buttinoni氏の素晴らしい仕事に感謝したいと思います。彼は、このクエリをさらに高速化するいくつかの巧妙な方法を見つけました。

ストーリーの教訓:メインクエリの外に置くことでORDER BY高速化できる のは句だけではありません。このような状況では、WHERE 句の一部をその外側に配置することで高速なクエリを取得することもできます。

于 2012-12-05T15:38:25.977 に答える
0

table1.col6 の型は何ですか? そのフィールド直径 (最大値の長さ) は?

ところで、Ivan Buttinoniが提案したように、フィールド値に依存しない値を事前に計算します。順序付けには役立ちませんが、クエリが高速になります

于 2012-11-27T12:12:13.690 に答える