ฉันควรใช้ UUID เช่นเดียวกับ ID


11

ฉันใช้ UUID ในระบบของฉันมาระยะหนึ่งแล้วด้วยเหตุผลหลายประการตั้งแต่การบันทึกไปจนถึงความสัมพันธ์ที่ล่าช้า รูปแบบที่ฉันใช้เปลี่ยนไปเมื่อฉันไร้เดียงสาน้อยลงจาก:

  1. VARCHAR(255)
  2. VARCHAR(36)
  3. CHAR(36)
  4. BINARY(16)

เมื่อฉันไปถึงขั้นสุดท้ายBINARY(16)ที่ฉันเริ่มเปรียบเทียบประสิทธิภาพกับจำนวนเต็มพื้นฐานที่เพิ่มขึ้นอัตโนมัติ การทดสอบและผลลัพธ์แสดงไว้ด้านล่าง แต่ถ้าคุณต้องการสรุปก็แสดงว่าINT AUTOINCREMENTและBINARY(16) RANDOMมีประสิทธิภาพเหมือนกันในช่วงข้อมูลสูงสุด 200,000 (ฐานข้อมูลถูกเติมข้อมูลล่วงหน้าก่อนการทดสอบ)

ตอนแรกฉันสงสัยว่าจะใช้ UUID เป็นคีย์หลักและแน่นอนฉันก็ยังอยู่ แต่ฉันเห็นศักยภาพที่นี่เพื่อสร้างฐานข้อมูลที่ยืดหยุ่นที่สามารถใช้ทั้งสองได้ ในขณะที่หลายคนเครียดกับข้อได้เปรียบของทั้งสองข้อเสียอะไรที่ถูกยกเลิกโดยการใช้ข้อมูลทั้งสองชนิด?

  • PRIMARY INT
  • UNIQUE BINARY(16)

กรณีการใช้งานสำหรับการตั้งค่าประเภทนี้จะเป็นคีย์หลักดั้งเดิมสำหรับความสัมพันธ์ระหว่างตารางโดยมีตัวระบุเฉพาะที่ใช้สำหรับความสัมพันธ์ระหว่างระบบ

สิ่งที่ฉันพยายามค้นพบเป็นหลักคือประสิทธิภาพที่แตกต่างระหว่างสองแนวทาง นอกเหนือจากพื้นที่ดิสก์สี่เท่าที่ใช้ซึ่งอาจเล็กน้อยมากหลังจากเพิ่มข้อมูลเพิ่มเติมพวกเขาดูเหมือนจะเหมือนกัน

schema:

-- phpMyAdmin SQL Dump
-- version 4.0.10deb1
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Sep 22, 2015 at 10:54 AM
-- Server version: 5.5.44-0ubuntu0.14.04.1
-- PHP Version: 5.5.29-1+deb.sury.org~trusty+3

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- Database: `test`
--

-- --------------------------------------------------------

--
-- Table structure for table `with_2id`
--

CREATE TABLE `with_2id` (
  `guidl` bigint(20) NOT NULL,
  `guidr` bigint(20) NOT NULL,
  `data` varchar(255) NOT NULL,
  PRIMARY KEY (`guidl`,`guidr`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- --------------------------------------------------------

--
-- Table structure for table `with_guid`
--

CREATE TABLE `with_guid` (
  `guid` binary(16) NOT NULL,
  `data` varchar(255) NOT NULL,
  PRIMARY KEY (`guid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- --------------------------------------------------------

--
-- Table structure for table `with_id`
--

CREATE TABLE `with_id` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `data` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=197687 ;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

แทรกมาตรฐาน:

function benchmark_insert(PDO $pdo, $runs)
{
    $data = 'Sample Data';

    $insert1 = $pdo->prepare("INSERT INTO with_id (data) VALUES (:data)");
    $insert1->bindParam(':data', $data);

    $insert2 = $pdo->prepare("INSERT INTO with_guid (guid, data) VALUES (:guid, :data)");
    $insert2->bindParam(':guid', $guid);
    $insert2->bindParam(':data', $data);

    $insert3 = $pdo->prepare("INSERT INTO with_2id (guidl, guidr, data) VALUES (:guidl, :guidr, :data)");
    $insert3->bindParam(':guidl', $guidl);
    $insert3->bindParam(':guidr', $guidr);
    $insert3->bindParam(':data',  $data);

    $benchmark = array();

    $time = time();
    for ($i = 0; $i < $runs; $i++) {
        $insert1->execute();
    }
    $benchmark[1] = 'INC ID:     ' . (time() - $time);

    $time = time();
    for ($i = 0; $i < $runs; $i++) {
        $guid  = openssl_random_pseudo_bytes(16);

        $insert2->execute();
    }
    $benchmark[2] = 'GUID:       ' . (time() - $time);

    $time = time();
    for ($i = 0; $i < $runs; $i++) {
        $guid  = openssl_random_pseudo_bytes(16);
        $guidl = unpack('q', substr($guid, 0, 8))[1];
        $guidr = unpack('q', substr($guid, 8, 8))[1];

        $insert3->execute();
    }
    $benchmark[3] = 'SPLIT GUID: ' . (time() - $time);

    echo 'INSERTION' . PHP_EOL;
    echo '=============================' . PHP_EOL;
    echo $benchmark[1] . PHP_EOL;
    echo $benchmark[2] . PHP_EOL;
    echo $benchmark[3] . PHP_EOL . PHP_EOL;
}

เลือกมาตรฐาน:

function benchmark_select(PDO $pdo, $runs) {
    $select1 = $pdo->prepare("SELECT * FROM with_id WHERE id = :id");
    $select1->bindParam(':id', $id);

    $select2 = $pdo->prepare("SELECT * FROM with_guid WHERE guid = :guid");
    $select2->bindParam(':guid', $guid);

    $select3 = $pdo->prepare("SELECT * FROM with_2id WHERE guidl = :guidl AND guidr = :guidr");
    $select3->bindParam(':guidl', $guidl);
    $select3->bindParam(':guidr', $guidr);

    $keys = array();

    for ($i = 0; $i < $runs; $i++) {
        $kguid  = openssl_random_pseudo_bytes(16);
        $kguidl = unpack('q', substr($kguid, 0, 8))[1];
        $kguidr = unpack('q', substr($kguid, 8, 8))[1];
        $kid = mt_rand(0, $runs);

        $keys[] = array(
            'guid'  => $kguid,
            'guidl' => $kguidl,
            'guidr' => $kguidr,
            'id'    => $kid
        );
    }

    $benchmark = array();

    $time = time();
    foreach ($keys as $key) {
        $id = $key['id'];
        $select1->execute();
        $row = $select1->fetch(PDO::FETCH_ASSOC);
    }
    $benchmark[1] = 'INC ID:     ' . (time() - $time);


    $time = time();
    foreach ($keys as $key) {
        $guid = $key['guid'];
        $select2->execute();
        $row = $select2->fetch(PDO::FETCH_ASSOC);
    }
    $benchmark[2] = 'GUID:       ' . (time() - $time);

    $time = time();
    foreach ($keys as $key) {
        $guidl = $key['guidl'];
        $guidr = $key['guidr'];
        $select3->execute();
        $row = $select3->fetch(PDO::FETCH_ASSOC);
    }
    $benchmark[3] = 'SPLIT GUID: ' . (time() - $time);

    echo 'SELECTION' . PHP_EOL;
    echo '=============================' . PHP_EOL;
    echo $benchmark[1] . PHP_EOL;
    echo $benchmark[2] . PHP_EOL;
    echo $benchmark[3] . PHP_EOL . PHP_EOL;
}

แบบทดสอบ:

$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');

benchmark_insert($pdo, 1000);
benchmark_select($pdo, 100000);

ผล:

INSERTION
=============================
INC ID:     3
GUID:       2
SPLIT GUID: 3

SELECTION
=============================
INC ID:     5
GUID:       5
SPLIT GUID: 6

คำตอบ:


10

UUIDs เป็นความเสียหายด้านประสิทธิภาพสำหรับตารางที่มีขนาดใหญ่มาก (200K แถวไม่ใช่ "ใหญ่มาก")

# 3 ของคุณไม่ดีจริง ๆ เมื่อCHARCTER SETutf8 - CHAR(36)มี 108 ไบต์! ปรับปรุง: มีROW_FORMATsสิ่งนี้จะอยู่ที่ 36

UUIDs (GUID) เป็น "สุ่ม" มาก ใช้เป็น UNIQUE หรือคีย์หลักในตารางขนาดใหญ่ไม่มีประสิทธิภาพมาก เนื่องจากต้องข้ามไปที่ตาราง / ดัชนีทุกครั้งที่คุณINSERTมี UUID ใหม่หรือSELECTโดย UUID เมื่อตาราง / ดัชนีมีขนาดใหญ่เกินกว่าที่จะพอดีกับแคช (ดูinnodb_buffer_pool_sizeซึ่งต้องมีขนาดเล็กกว่า RAM โดยทั่วไป 70%) UUID 'ถัดไป' อาจไม่ถูกแคชดังนั้นจึงเป็นดิสก์ที่ช้า เมื่อตาราง / ดัชนีใหญ่กว่าแคช 20 เท่ามีการแคชเฉพาะ 1 / 20th (5%) ของการเข้าชมคุณเป็น I / O-bound ลักษณะทั่วไป: ความไร้ประสิทธิภาพใช้กับการเข้าถึงแบบ "สุ่ม" - UUID / MD5 / RAND () / ฯลฯ

ดังนั้นอย่าใช้ UUID เว้นแต่ว่าจะเป็นอย่างใดอย่างหนึ่ง

  • คุณมีตาราง "เล็ก" หรือ
  • คุณต้องการพวกเขาจริงๆเพราะสร้างรหัสที่ไม่เหมือนใครจากสถานที่ต่าง ๆ (และยังไม่สามารถหาวิธีอื่นได้)

เพิ่มเติมเกี่ยวกับ UUIDs: http://mysql.rjweb.org/doc.php/uuid (รวมถึงฟังก์ชั่นสำหรับการแปลงระหว่างมาตรฐาน 36-char UUIDsและBINARY(16).) การ ปรับปรุง: MySQL 8.0 มีฟังก์ชั่นในตัวเช่น

การมีทั้ง UNIQUE AUTO_INCREMENTและUNIQUEUUID ในตารางเดียวกันเป็นของเสีย

  • เมื่อINSERTเกิดขึ้นจะต้องตรวจสอบคีย์ที่ไม่ซ้ำกัน / คีย์หลักทั้งหมดเพื่อทำซ้ำ
  • อย่างใดอย่างหนึ่งที่สำคัญที่ไม่ซ้ำกันก็เพียงพอสำหรับความต้องการของ InnoDB PRIMARY KEYของการมี
  • BINARY(16) (16 ไบต์) ค่อนข้างใหญ่ (มีข้อโต้แย้งในการทำให้เป็น PK) แต่ก็ไม่ได้แย่ขนาดนั้น
  • ความใหญ่โตมีความสำคัญเมื่อคุณมีคีย์รอง InnoDB จะดึง PK ไปยังจุดสุดท้ายของแต่ละคีย์รองอย่างเงียบ ๆ บทเรียนหลักที่นี่คือการลดจำนวนของรองคีย์โดยเฉพาะอย่างยิ่งสำหรับตารางที่มีขนาดใหญ่มาก การทำอย่างประณีต: สำหรับกุญแจดอกรองอันที่หนึ่งการถกเถียงที่เป็นกลุ่มมักจะจบลงด้วยการเสมอกัน สำหรับคีย์รอง 2 ตัวหรือมากกว่านั้น PK ที่อ้วนขึ้นมักจะนำไปสู่รอยเท้าของดิสก์ที่ใหญ่กว่าสำหรับตารางรวมถึงดัชนีของมัน

สำหรับการเปรียบเทียบ: INT UNSIGNEDคือ 4 ไบต์โดยมีช่วง 0..4 พันล้าน BIGINTคือ 8 ไบต์

อัพเดทตัวเอียง / อื่น ๆ ถูกเพิ่ม Sep, 2017; ไม่มีอะไรเปลี่ยนแปลงที่สำคัญ


ขอบคุณสำหรับคำตอบของคุณฉันไม่ได้ตระหนักถึงการสูญเสียการเพิ่มประสิทธิภาพแคช ฉันกังวลน้อยเกี่ยวกับกุญแจต่างประเทศขนาดใหญ่ แต่ฉันเห็นว่าในที่สุดมันจะกลายเป็นปัญหาได้อย่างไร ฉันลังเลที่จะลบการใช้งานออกไปอย่างสิ้นเชิง แต่ก็พิสูจน์ได้ว่ามีประโยชน์มากสำหรับการโต้ตอบข้ามระบบ BINARY(16)ฉันคิดว่าเราทั้งคู่เห็นด้วยเป็นวิธีที่มีประสิทธิภาพที่สุดในการจัดเก็บ UUID แต่เกี่ยวกับUNIQUEดัชนีฉันควรใช้ดัชนีปกติหรือไม่ ไบต์ถูกสร้างขึ้นโดยใช้ RNG ที่ปลอดภัยด้วยการเข้ารหัสดังนั้นฉันจะขึ้นอยู่กับการสุ่มทั้งหมดและยกเลิกการตรวจสอบหรือไม่
Flosculus

ดัชนีที่ไม่ซ้ำกันจะช่วยให้ประสิทธิภาพการทำงานบางอย่าง แต่แม้จะต้องมีการปรับปรุงดัชนีปกติในที่สุด ขนาดตารางที่ฉายของคุณคืออะไร ในที่สุดมันจะใหญ่เกินไปที่จะแคชหรือไม่ ค่าที่แนะนำสำหรับinnodb_buffer_pool_sizeคือ 70% ของ RAM ที่มีอยู่
Rick James

ฐานข้อมูล 1.2 GB หลังจาก 2 เดือนตารางที่ใหญ่ที่สุดคือ 300MB แต่ข้อมูลจะไม่หายไปดังนั้นอาจนานถึง 10 ปี ได้รับน้อยกว่าครึ่งหนึ่งของตารางจะต้องมี UUIDs ดังนั้นฉันจะลบพวกเขาออกจากกรณีการใช้งานที่ตื้นที่สุด ซึ่งปล่อยสิ่งที่ต้องการในปัจจุบันที่ 50,000 แถวและ 250MB หรือ 30 - 100 GB ใน 10 ปี
Flosculus

2
ใน 10 ปีคุณจะไม่สามารถซื้อเครื่องที่มี RAM เพียง 100GB คุณมักจะพอดีกับ RAM ดังนั้นความคิดเห็นของฉันอาจไม่เหมาะกับกรณีของคุณ
Rick James

1
@a_horse_with_no_name - ในรุ่นที่เก่ากว่ามันจะเป็น 3 เท่าเสมอ เฉพาะรุ่นที่ใหม่กว่าเท่านั้นที่ฉลาดพอสมควร บางทีนั่นอาจเป็น 5.1.24; นั่นอาจจะเก่าแก่พอที่ฉันจะลืมมันได้
Rick James

2

'Rick James' ตอบด้วยคำตอบที่ยอมรับได้: "การมีทั้ง UNIQUE AUTO_INCREMENT และ UNIQUE UUID ในตารางเดียวกันนั้นเป็นของเสีย" แต่การทดสอบนี้ (ฉันทำในเครื่องของฉัน) แสดงข้อเท็จจริงต่าง ๆ

ตัวอย่างเช่น: ด้วยการทดสอบ (T2) ฉันสร้างตารางด้วย (INT AUTOINCREMENT) ประถมและไม่ซ้ำกันไบนารี (16) และเขตข้อมูลอื่นเป็นชื่อเรื่องจากนั้นฉันแทรกแถวมากกว่า 1.6 ล้านแถวด้วยประสิทธิภาพที่ดีมาก แต่ด้วยการทดสอบอื่น (T3) ฉันทำเช่นเดียวกัน แต่ผลลัพธ์ช้าหลังจากแทรก 300,000 แถวเท่านั้น

นี่คือผลการทดสอบของฉัน:

T1:
char(32) UNIQUE with auto increment int_id
after: 1,600,000
10 sec for inserting 1000 rows
select + (4.0)
size:500mb

T2:
binary(16) UNIQUE with auto increment int_id
after: 1,600,000
1 sec for inserting 1000 rows
select +++ (0.4)
size:350mb

T3:
binary(16) UNIQUE without auto increment int_id
after: 350,000
5 sec for inserting 1000 rows
select ++ (0.3)
size:118mb (~ for 1,600,000 will be 530mb)

T4:
auto increment int_id without binary(16) UNIQUE
++++

T5:
uuid_short() int_id without binary(16) UNIQUE
+++++*

ดังนั้น binary (16) UNIQUE ที่มีการเพิ่มค่าอัตโนมัติ int_id ดีกว่า binary (16) UNIQUE ที่ไม่มีการเพิ่มค่าอัตโนมัติ int_id

ปรับปรุง:

ฉันทำแบบทดสอบเดียวกันอีกครั้งและบันทึกรายละเอียดเพิ่มเติม นี่คือรหัสเต็มและการเปรียบเทียบผลลัพธ์ระหว่าง (T2) และ (T3) ตามที่อธิบายไว้ข้างต้น

(T2) สร้าง tbl2 (mysql):

CREATE TABLE test.tbl2 (
  int_id INT(11) NOT NULL AUTO_INCREMENT,
  rec_id BINARY(16) NOT NULL,
  src_id BINARY(16) DEFAULT NULL,
  rec_title VARCHAR(255) DEFAULT NULL,
  PRIMARY KEY (int_id),
  INDEX IDX_tbl1_src_id (src_id),
  UNIQUE INDEX rec_id (rec_id)
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;

(T3) สร้าง tbl3 (mysql):

CREATE TABLE test.tbl3 (
  rec_id BINARY(16) NOT NULL,
  src_id BINARY(16) DEFAULT NULL,
  rec_title VARCHAR(255) DEFAULT NULL,
  PRIMARY KEY (rec_id),
  INDEX IDX_tbl1_src_id (src_id)
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;

นี่คือรหัสทดสอบเต็มรูปแบบโดยมีการแทรกบันทึก 600,000 รายการลงใน tbl2 หรือ tbl3 (รหัส vb.net):

Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim res As String = ""
        Dim i As Integer = 0
        Dim ii As Integer = 0
        Dim iii As Integer = 0

        Using cn As New SqlClient.SqlConnection
            cn.ConnectionString = "Data Source=.\sql2008;Integrated Security=True;User Instance=False;MultipleActiveResultSets=True;Initial Catalog=sourcedb;"
            cn.Open()
            Using cmd As New SqlClient.SqlCommand
                cmd.Connection = cn
                cmd.CommandTimeout = 0
                cmd.CommandText = "select recID, srcID, rectitle from textstbl order by ID ASC"

                Using dr As SqlClient.SqlDataReader = cmd.ExecuteReader

                    Using mysqlcn As New MySql.Data.MySqlClient.MySqlConnection
                        mysqlcn.ConnectionString = "User Id=root;Host=localhost;Character Set=utf8;Pwd=1111;Database=test"
                        mysqlcn.Open()

                        Using MyCommand As New MySql.Data.MySqlClient.MySqlCommand
                            MyCommand.Connection = mysqlcn

                            MyCommand.CommandText = "insert into tbl3 (rec_id, src_id, rec_title) values (UNHEX(@rec_id), UNHEX(@src_id), @rec_title);"
                            Dim MParm1(2) As MySql.Data.MySqlClient.MySqlParameter
                            MParm1(0) = New MySql.Data.MySqlClient.MySqlParameter("@rec_id", MySql.Data.MySqlClient.MySqlDbType.String)
                            MParm1(1) = New MySql.Data.MySqlClient.MySqlParameter("@src_id", MySql.Data.MySqlClient.MySqlDbType.String)
                            MParm1(2) = New MySql.Data.MySqlClient.MySqlParameter("@rec_title", MySql.Data.MySqlClient.MySqlDbType.VarChar)

                            MyCommand.Parameters.AddRange(MParm1)
                            MyCommand.CommandTimeout = 0

                            Dim mytransaction As MySql.Data.MySqlClient.MySqlTransaction = mysqlcn.BeginTransaction()
                            MyCommand.Transaction = mytransaction

                            Dim sw As New Stopwatch
                            sw.Start()

                            While dr.Read
                                MParm1(0).Value = dr.GetValue(0).ToString.Replace("-", "")
                                MParm1(1).Value = EmptyStringToNullValue(dr.GetValue(1).ToString.Replace("-", ""))
                                MParm1(2).Value = gettitle(dr.GetValue(2).ToString)

                                MyCommand.ExecuteNonQuery()

                                i += 1
                                ii += 1
                                iii += 1

                                If i >= 1000 Then
                                    i = 0

                                    Dim ts As TimeSpan = sw.Elapsed
                                    Me.Text = ii.ToString & " / " & ts.TotalSeconds

                                    Select Case ii
                                        Case 10000, 50000, 100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000
                                            res &= "On " & FormatNumber(ii, 0) & ": last inserting 1000 records take: " & ts.TotalSeconds.ToString & " second." & vbCrLf
                                    End Select

                                    If ii >= 600000 Then GoTo 100
                                    sw.Restart()
                                End If
                                If iii >= 5000 Then
                                    iii = 0

                                    mytransaction.Commit()
                                    mytransaction = mysqlcn.BeginTransaction()

                                    sw.Restart()
                                End If
                            End While
100:
                            mytransaction.Commit()

                        End Using
                    End Using
                End Using
            End Using
        End Using

        TextBox1.Text = res
        MsgBox("Ok!")
    End Sub

    Public Function EmptyStringToNullValue(MyValue As Object) As Object
        'On Error Resume Next
        If MyValue Is Nothing Then Return DBNull.Value
        If String.IsNullOrEmpty(MyValue.ToString.Trim) Then
            Return DBNull.Value
        Else
            Return MyValue
        End If
    End Function

    Private Function gettitle(p1 As String) As String
        If p1.Length > 255 Then
            Return p1.Substring(0, 255)
        Else
            Return p1
        End If
    End Function

End Class

ผลลัพธ์สำหรับ (T2):

On 10,000: last inserting 1000 records take: 0.13709 second.
On 50,000: last inserting 1000 records take: 0.1772109 second.
On 100,000: last inserting 1000 records take: 0.1291394 second.
On 200,000: last inserting 1000 records take: 0.5793488 second.
On 300,000: last inserting 1000 records take: 0.1296427 second.
On 400,000: last inserting 1000 records take: 0.6938583 second.
On 500,000: last inserting 1000 records take: 0.2317799 second.
On 600,000: last inserting 1000 records take: 0.1271072 second.

~3 Minutes ONLY! to insert 600,000 records.
table size: 128 mb.

ผลลัพธ์สำหรับ (T3):

On 10,000: last inserting 1000 records take: 0.1669595 second.
On 50,000: last inserting 1000 records take: 0.4198369 second.
On 100,000: last inserting 1000 records take: 0.1318155 second.
On 200,000: last inserting 1000 records take: 0.1979358 second.
On 300,000: last inserting 1000 records take: 1.5127482 second.
On 400,000: last inserting 1000 records take: 7.2757161 second.
On 500,000: last inserting 1000 records take: 14.3960671 second.
On 600,000: last inserting 1000 records take: 14.9412401 second.

~40 Minutes! to insert 600,000 records.
table size: 164 mb.

2
โปรดอธิบายว่าคำตอบของคุณเป็นอย่างไรมากกว่าแค่การใช้เกณฑ์มาตรฐานในเครื่องส่วนตัวของคุณ คำตอบที่ดีเลิศจะพูดถึงการแลกเปลี่ยนบางส่วนที่เกี่ยวข้องแทนที่จะเป็นเพียงแค่เกณฑ์มาตรฐาน
Erik

1
กรุณาอธิบาย อะไรคือสิ่งที่innodb_buffer_pool_size? "ขนาดตาราง" มาจากไหน
Rick James

1
โปรดเรียกใช้อีกครั้งโดยใช้ 1,000 สำหรับขนาดการทำธุรกรรม - นี่อาจกำจัด hiccups ที่แปลกในทั้ง tbl2 และ tbl3 นอกจากนี้พิมพ์เวลาหลังจากCOMMITไม่ก่อน นี่อาจกำจัดความผิดปกติอื่น ๆ
Rick James

1
ฉันไม่คุ้นเคยกับภาษาที่คุณใช้ แต่ฉันเห็นคุณค่าของความแตกต่างของ@rec_idและ@src_idการสร้างและนำไปใช้กับแต่ละแถว การพิมพ์ข้อความสองสามINSERTข้ออาจทำให้ฉันพึงพอใจ
Rick James

1
นอกจากนี้เดินต่อไป 600K ณ จุดหนึ่ง (บางส่วนขึ้นอยู่กับว่า rec_title ใหญ่แค่ไหน) t2ก็จะตกจากหน้าผา มันอาจช้ากว่าt3; ฉันไม่แน่ใจ. มาตรฐานของคุณอยู่ใน "หลุมโดนัท" ซึ่งt3เป็นชั่วคราวช้าลง
Rick James
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.