Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Kinerja kueri pada kolom Boolean yang diindeks vs kolom Datetime

Berikut adalah tolok ukur MariaDB (10.0.19) dengan 10 juta baris (menggunakan plugin urutan ):

drop table if exists test;
CREATE TABLE `test` (
    `id` MEDIUMINT UNSIGNED NOT NULL,
    `is_active` TINYINT UNSIGNED NOT NULL,
    `deleted_at` TIMESTAMP NULL,
    PRIMARY KEY (`id`),
    INDEX `is_active` (`is_active`),
    INDEX `deleted_at` (`deleted_at`)
) ENGINE=InnoDB
    select seq id
        , rand(1)<0.5 as is_active
        , case when rand(1)<0.5 
            then null
            else '2017-03-18' - interval floor(rand(2)*1000000) second
        end as deleted_at
    from seq_1_to_10000000;

Untuk mengukur waktu saya menggunakan set profiling=1 dan jalankan show profile setelah menjalankan kueri. Dari hasil profileing saya ambil nilai Sending data karena semuanya kurang dari satu mdtk.

TINYINT indeks:

SELECT COUNT(*) FROM test WHERE is_active = 1;

Waktu Proses:~ 738 mdtk

TIMESTAMP indeks:

SELECT COUNT(*) FROM test WHERE  deleted_at is null;

Waktu Proses:~ 748 mdtk

Ukuran indeks:

select database_name, table_name, index_name, stat_value*@@innodb_page_size
from mysql.innodb_index_stats 
where database_name = 'tmp'
  and table_name = 'test'
  and stat_name = 'size'

Hasil:

database_name | table_name | index_name | stat_value*@@innodb_page_size
-----------------------------------------------------------------------
tmp           | test       | PRIMARY    | 275513344 
tmp           | test       | deleted_at | 170639360 
tmp           | test       | is_active  |  97107968 

Perhatikan bahwa sementara TIMESTAMP (4 Byte) adalah 4 kali lebih panjang dari TYNYINT (1 Byte), ukuran indeks bahkan tidak dua kali lebih besar. Tetapi ukuran indeks bisa menjadi signifikan jika tidak sesuai dengan memori. Jadi ketika saya mengubah innodb_buffer_pool_size dari 1G ke 50M saya mendapatkan nomor berikut:

  • TINYINT:~ 960 mdtk
  • TIMESTAMP:~ 1500 mdtk

Perbarui

Untuk menjawab pertanyaan secara lebih langsung, saya melakukan beberapa perubahan pada data:

  • Alih-alih TIMESTAMP saya menggunakan DATETIME
  • Karena entri biasanya jarang dihapus, saya menggunakan rand(1)<0.99 (1% dihapus) alih-alih rand(1)<0.5 (50% dihapus)
  • Ukuran tabel diubah dari 10 juta menjadi 1 juta baris.
  • SELECT COUNT(*) diubah menjadi SELECT *

Ukuran indeks:

index_name | stat_value*@@innodb_page_size
------------------------------------------
PRIMARY    | 25739264
deleted_at | 12075008
is_active  | 11026432

Sejak 99% dari deleted_at nilainya NULL tidak ada perbedaan signifikan dalam ukuran indeks, meskipun DATETIME yang tidak kosong membutuhkan 8 Bytes (MariaDB).

SELECT * FROM test WHERE is_active = 1;      -- 782 msec
SELECT * FROM test WHERE deleted_at is null; -- 829 msec

Menjatuhkan kedua indeks, kedua kueri dieksekusi dalam waktu sekitar 350 mdtk. Dan menghapus is_active kolom deleted_at is null kueri dijalankan dalam 280 mdtk.

Perhatikan bahwa ini masih bukan skenario yang realistis. Anda mungkin tidak ingin memilih 990 ribu baris dari 1 juta dan mengirimkannya ke pengguna. Anda mungkin juga akan memiliki lebih banyak kolom (mungkin termasuk teks) dalam tabel. Tetapi ini menunjukkan, bahwa Anda mungkin tidak memerlukan is_active kolom (jika tidak menambahkan informasi tambahan), dan bahwa indeks apa pun dalam kasus terbaik tidak berguna untuk memilih entri yang tidak dihapus.

Namun indeks dapat berguna untuk memilih baris yang dihapus:

SELECT * FROM test WHERE is_active = 0;

Dieksekusi dalam 10 mdtk dengan indeks dan dalam 170 mdtk tanpa indeks.

SELECT * FROM test WHERE deleted_at is not null;

Dieksekusi dalam 11 mdtk dengan indeks dan dalam 167 mdtk tanpa indeks.

Menjatuhkan is_active kolom itu dijalankan dalam 4 mdtk dengan indeks dan dalam 150 mdtk tanpa indeks.

Jadi, jika skenario ini cocok dengan data Anda, kesimpulannya adalah:Lepaskan is_active kolom dan jangan buat indeks pada deleted_at kolom jika Anda jarang memilih entri yang dihapus. Atau sesuaikan tolok ukur dengan kebutuhan Anda dan buat kesimpulan sendiri.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Apa yang Baru Dengan Replikasi MySQL di MySQL 8.0

  2. java.sql.SQLException:Nilai argumen tidak valid:java.io.NotSerializableException

  3. Adakah yang bisa menjelaskan kunci asing MySQL?

  4. Alternatif MySQL untuk T-SQL's WITH TIES

  5. Konversikan BIGINT TANPA TANDATANGAN ke INT