Cara optimize query JOIN 2 Table

29 views
Skip to first unread message

akbar maulana

unread,
Dec 13, 2018, 4:21:08 AM12/13/18
to MySQL Indonesia
# Table name: entities
#  id                     :integer          not null, primary key

# Table name: risks
#  id         :integer          not null, primary key
#  entity_id  :integer
#  observable :string
    t.index ["entity_id"], name: "index_risks_on_entity_id"
    t.index ["id"], name: "index_risks_on_id", unique: true
    t.index ["observable", "entity_id"], name: "index_risks_on_observable_and_entity_id"

# Table name: transactions
#  id                         :integer          not null, primary key
#  originator_id              :integer
#  beneficiary_id             :integer
    t.index ["beneficiary_id"], name: "index_transactions_on_beneficiary_id"
    t.index ["originator_id"], name: "index_transactions_on_originator_id"

query saya seperti ini :
SELECT * FROM entities INNER JOIN transactions ON transactions.originator_id = entities.id OR transactions.beneficiary_id = entities.id INNER JOIN risks ON risks.entity_id = entities.id AND risks.observable = 'segmentation'

query diatas membutuhkan waktu 7s-10s

para master sql bagaimana query paling optimal...salam advance

Natali Ardianto

unread,
Dec 14, 2018, 12:06:32 AM12/14/18
to MySQL Indonesia
Coba jalankan ini dan paste disini:

EXPLAIN EXTENDED SELECT * FROM entities INNER JOIN transactions ON transactions.originator_id = entities.id OR transactions.beneficiary_id = entities.id INNER JOIN risks ON risks.entity_id = entities.id AND risks.observable = 'segmentation'

Atau dump DDL nya kesini (dump query struktur)

SHOW CREATE TABLE entities;
SHOW CREATE TABLE risks;
SHOW CREATE TABLE transactions;

akbar maulana

unread,
Dec 14, 2018, 1:57:46 AM12/14/18
to MySQL Indonesia
btw saya pakai rails, kalau di explain hasilnya ini :
 
Gather  (cost=258675.86..823834.23 rows=142148 width=388)
   Workers Planned: 2
   ->  Merge Join  (cost=257675.86..808619.43 rows=59228 width=388)
         Merge Cond: (entities.id = risks.entity_id)
         ->  Nested Loop  (cost=1.29..1672403.86 rows=166675 width=388)
               ->  Parallel Index Scan using index_entities_on_id on entities  (cost=0.42..35122.66 rows=333356 width=388)
               ->  Bitmap Heap Scan on transactions  (cost=0.86..4.89 rows=2 width=8)
                     Recheck Cond: ((originator_id = entities.id) OR (beneficiary_id = entities.id))
                     ->  BitmapOr  (cost=0.86..0.86 rows=2 width=0)
                           ->  Bitmap Index Scan on index_transactions_on_originator_id  (cost=0.00..0.43 rows=1 width=0)
                                 Index Cond: (originator_id = entities.id)
                           ->  Bitmap Index Scan on index_transactions_on_beneficiary_id  (cost=0.00..0.43 rows=1 width=0)
                                 Index Cond: (beneficiary_id = entities.id)
         ->  Materialize  (cost=257654.50..259076.01 rows=284301 width=4)
               ->  Sort  (cost=257654.50..258365.25 rows=284301 width=4)
                     Sort Key: risks.entity_id
                     ->  Bitmap Heap Scan on risks  (cost=7771.89..228012.51 rows=284301 width=4)
                           Recheck Cond: ((observable)::text = 'segmentation'::text)
                           ->  Bitmap Index Scan on index_risks_on_observable_and_entity_id  (cost=0.00..7700.82 rows=284301 width=0)
                                 Index Cond: ((observable)::text = 'segmentation'::text)

Natali Ardianto

unread,
Dec 14, 2018, 3:34:07 AM12/14/18
to mysql-i...@googlegroups.com
Heumm doesn't help. Pakai native MySQL saja.

idselect_typetabletypepossible_keyskeykey_lenrefrowsfilteredExtra
1SIMPLEentitiesindexPRIMARYPRIMARY4NULL1100.00Using index
1SIMPLEtransactionsALLoriginator_id,beneficiary_idNULLNULLNULL1100.00Range checked for each record (index map: 0x6)
1SIMPLErisksrefentity_id,observableobservable24const,test.entities.id1100.00Using where; Using index

Kelihatan kl index di table transactions tidak dipakai (type ALL).

Saya coba force index dan query nya saya pisah dan satukan pakai UNION karena index per table hanya bisa dipanggil sekali. Dan karena saya tidak bisa melihat isi datanya, jadi saya pakai asumsi ini (bisa juga join table dua kali).

explain EXTENDED 
SELECT * 
FROM entities 
INNER JOIN transactions force INDEX for join (originator_id) ON transactions.originator_id = entities.id 
INNER JOIN risks ON risks.entity_id =entities.id AND risks.observable = 'segmentation' 
UNION 
SELECT * FROM entities 
INNER JOIN transactions force INDEX for join (beneficiary_id) ON transactions.beneficiary_id =entities.id 
INNER JOIN risks ON risks.entity_id = entities.id AND risks.observable = 'segmentation'  

idselect_typetabletypepossible_keyskeykey_lenrefrowsfilteredExtra
1PRIMARYentitiesindexPRIMARYPRIMARY4NULL1100.00Using index
1PRIMARYtransactionsreforiginator_idoriginator_id4test.entities.id1100.00
1PRIMARYrisksrefentity_id,observableobservable24const,test.entities.id1100.00Using where; Using index
2UNIONentitiesindexPRIMARYPRIMARY4NULL1100.00Using index
2UNIONtransactionsrefbeneficiary_idbeneficiary_id4test.entities.id1100.00
2UNIONrisksrefentity_id,observableobservable24const,test.entities.id1100.00Using where; Using index
NULLUNION RESULT<union1,2>ALLNULLNULLNULLNULLNULLNULL






--
Untuk memposting, kirim email ke mysql-i...@googlegroups.com |
Untuk unsubscribe, kirim email ke mysql-indones...@googlegroups.com | Arsip milis : https://groups.google.com/d/forum/mysql-indonesia?hl=id
---
Anda menerima pesan ini karena berlangganan grup "MySQL Indonesia" di Google Grup.
Untuk berhenti berlangganan dan berhenti menerima email dari grup ini, kirim email ke mysql-indones...@googlegroups.com.
Untuk opsi lebih lanjut, kunjungi https://groups.google.com/d/optout.

akbar maulana

unread,
Dec 14, 2018, 4:53:06 AM12/14/18
to MySQL Indonesia
betul sekali, untuk index di transactions tidak kepakai karena saya pakai OR Clause, saya juga sudah mencoba menggunakan UNION kemarin namun muncul error seperti ini (begitu juga suggest query mas ardi)
`PG::DuplicateAlias: ERROR:  table name "transactions" specified more than once`, saya tahu persis kenapa muncul itu. karena terjadi join 2x ke transactions yang tidak di ALIAS dan setelah di kasih AS jadi begini :

SELECT * 
FROM entities 
INNER JOIN transactions AS orig ON orig.originator_id = entities.id 
INNER JOIN risks ON risks.entity_id =entities.id AND risks.observable = 'segmentation' 
UNION 
SELECT * FROM entities 
INNER JOIN transactions As ben ON ben.beneficiary_id = entities.id 
INNER JOIN risks ON risks.entity_id = entities.id AND risks.observable = 'segmentation'

untuk query diatas, index di beneficiary dan originator kepakai, kecepatan lumayan ningkat namun saya belum dapat mengimplementasikan di rails, karena .union di activerecord rails itu tidak ada T_T

akbar maulana

unread,
Dec 14, 2018, 5:30:49 AM12/14/18
to MySQL Indonesia
saya sudah ketemu gemnya untuk union di active record, dengan query diatas hasilnya menjadi 8s - 10s, mungkin memang sudah tidak bisa di optimize lagi ya

Natali Ardianto

unread,
Dec 14, 2018, 5:38:12 AM12/14/18
to mysql-i...@googlegroups.com
Bro, you are missing this:

FORCE INDEX FOR JOIN (originator_id)   

Pakai ini di rails:
query = <<-SQL
SELECT * 
FROM entities 
INNER JOIN transactions force INDEX for join (originator_id) ON transactions.originator_id = entities.id 
INNER JOIN risks ON risks.entity_id =entities.id AND risks.observable = 'segmentation' 
UNION 
SELECT * FROM entities 
INNER JOIN transactions force INDEX for join (beneficiary_id) ON transactions.beneficiary_id =entities.id 
INNER JOIN risks ON risks.entity_id = entities.id AND risks.observable = 'segmentation'  
SQL 
result = ActiveRecord::Base.connection.execute(query)
Sedangkan kalau query elo:

SELECT * 
FROM entities 
INNER JOIN transactions AS orig ON orig.originator_id = entities.id 
INNER JOIN risks ON risks.entity_id =entities.id AND risks.observable = 'segmentation' 
UNION 
SELECT * FROM entities 
INNER JOIN transactions As ben ON ben.beneficiary_id = entities.id 
INNER JOIN risks ON risks.entity_id = entities.id AND risks.observable = 'segmentation'
idselect_typetabletypepossible_keyskeykey_lenrefrowsfilteredExtra
1PRIMARYentitiesindexPRIMARYPRIMARY4NULL1100.00Using index
1PRIMARYorigALLoriginator_id
NULLNULLNULL1100.00
Using where; Using join buffer (flat, BNL join)
1PRIMARYrisksrefentity_id,observableobservable24const,test.entities.id1100.00Using where; Using index
2UNIONentitiesindexPRIMARYPRIMARY4NULL1100.00Using index
2UNIONbenALL
beneficiary_idNULLNULLNULL1100.00
Using where; Using join buffer (flat, BNL join)
2UNIONrisksrefentity_id,observableobservable24const,test.entities.id1100.00Using where; Using index
NULLUNION RESULT<union1,2>ALLNULLNULLNULLNULLNULLNULL

Bisa di lihat di baris kedua dan baris kelima, type ALL, itu full table scan. Sedangkan query saya semua pakai index.



Reply all
Reply to author
Forward
0 new messages