MySQL の暗黙的な変換について理解し理解する必要がある

運用環境では、SQL インデックスの失敗やパフォーマンスの極端な低下を引き起こす暗黙的な型変換が頻繁に発生し、クラスターの負荷とビジネスに影響を与えます。この記事では、暗黙的な変換の一般的なシナリオを要約します。運用環境では SQL の暗黙的な変換を避けるようにしてください。

著者: Zhang Luodan はデータベース テクノロジーに情熱を持っており、将来的にはより詳細な記事を執筆し、より価値のあるコンテンツを出力したいと考えています。

Aikeson オープンソース コミュニティによって作成されています。オリジナルのコンテンツを許可なく使用することはできません。転載する場合は編集者に連絡し、出典を明記してください。

この記事は約 3,000 ワードで、読むのに 10 分かかると予想されます。

SQL が暗黙的な変換を生成する一般的なシナリオには、次のようなものがあります。

  1. データ型の暗黙的な変換
  2. 文字セットの暗黙的な変換

中でも、文字セットの変換は、特にテーブル接続シナリオやストアド プロシージャで見落とされがちです。

注: 文字セットは、文字型データのエンコード規則です。数値型の場合、文字セットを変換する必要はありません。

データ型の暗黙的な変換

テストテーブルの構造

t1テーブルフィールドaは VARCHAR 型であり、t2テーブルフィールドaは INT 型です。

mysql> show create database test1\G
*************************** 1. row ***************************
       Database: test1
Create Database: CREATE DATABASE `test1` /*!40100 DEFAULT CHARACTER SET utf8 */
1 row in set (0.00 sec)
mysql> show create table t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `id` int(11) NOT NULL,
  `a` varchar(20) DEFAULT NULL,
  `b` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> show create table t2\G
*************************** 1. row ***************************
       Table: t2
Create Table: CREATE TABLE `t2` (
  `id` int(11) NOT NULL,
  `a` int(11) DEFAULT NULL,
  `b` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

単一テーブルの例

ここで注意が必要なのは、変換には次の 2 種類があるということです。

  1. フィールドの型が文字列型でパラメータが整数の場合、インデックスは失敗します。
  2. フィールドのタイプが整数で、受信パラメータが文字列タイプの場合、インデックスは失敗しません。

これは、文字列と数値を比較するときに、MySQL が比較のために文字列型を数値に変換するためです。そのため、フィールド型が文字列の場合、フィールドに関数が追加され、インデックスが失敗します。

公式ドキュメントでは次のように説明されています: 文字列は自動的に数値に変換され、必要に応じて数値は文字列に変換されます。

-- 字段类型为varchar,传参为整数,无法走到索引
mysql> explain select * from t1 where a=1000;
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | a             | NULL | NULL    | NULL | 498892 |    10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
1 row in set, 3 warnings (0.00 sec)
mysql> show warnings;
+---------+------+---------------------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                           |
+---------+------+---------------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 1739 | Cannot use ref access on index 'a' due to type or collation conversion on field 'a'                                                               |
| Warning | 1739 | Cannot use range access on index 'a' due to type or collation conversion on field 'a'                                                             |
| Note    | 1003 | /* select#1 */ select `test1`.`t1`.`id` AS `id`,`test1`.`t1`.`a` AS `a`,`test1`.`t1`.`b` AS `b` from `test1`.`t1` where (`test1`.`t1`.`a` = 1000) |
+---------+------+---------------------------------------------------------------------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)
-- 字段类型为int,传参为字符串,可以走到索引
mysql> explain select * from t2 where a='1000';
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t2    | NULL       | ref  | a             | a    | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

比較のために数値を文字列に変換できないのはなぜですか?

以下の比較結果:

  • 文字列の比較は、異なる文字が見つかるまで文字列のサイズを 1 つずつ比較します。この比較の結果は、数値の比較結果とは異なります。
mysql> select '2000' <'250';
+---------------+
| '2000' <'250' |
+---------------+
|             1 |
+---------------+
1 row in set (0.00 sec)

テーブル結合でのデータ型変換

2 つのテーブルの接続フィールドの型が一致しない場合、暗黙的な変換 (MySQL 内部cast()関数の追加) が発生し、接続フィールドのインデックスに到達できず、最適なテーブル接続順序が使用されない可能性があります。

インデックスが使用できないため、元々駆動テーブルだったテーブルが駆動テーブルとして使用される可能性があります。

例:

  • 次のように、通常の状況ではt2テーブルが駆動テーブルとして選択されますが、データ型が異なるため、実際に実行される SQL は次のようになります。select * from t1 join t2 on cast(t1.a as unsigned)=t2.a where t2.id<1000
  • 駆動テーブルとして使用される場合、のインデックスt1に移動する方法がないため、テーブルが駆動テーブルとして選択されます。t1.at1
mysql> explain select * from t1 join t2 on t1.a=t2.a where t2.id<1000;
+----+-------------+-------+------------+------+---------------+------+---------+------------+--------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref        | rows   | filtered | Extra                 |
+----+-------------+-------+------------+------+---------------+------+---------+------------+--------+----------+-----------------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | a             | NULL | NULL    | NULL       | 498892 |   100.00 | Using where           |
|  1 | SIMPLE      | t2    | NULL       | ref  | PRIMARY,a     | a    | 5       | test1.t1.a |      1 |     5.00 | Using index condition |
+----+-------------+-------+------------+------+---------------+------+---------+------------+--------+----------+-----------------------+
2 rows in set, 2 warnings (0.00 sec)
mysql> show warnings;
+---------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                                                                                                                                    |
+---------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 1739 | Cannot use ref access on index 'a' due to type or collation conversion on field 'a'                                                                                                                                                                                                        |
| Note    | 1003 | /* select#1 */ select `test1`.`t1`.`id` AS `id`,`test1`.`t1`.`a` AS `a`,`test1`.`t1`.`b` AS `b`,`test1`.`t2`.`id` AS `id`,`test1`.`t2`.`a` AS `a`,`test1`.`t2`.`b` AS `b` from `test1`.`t1` join `test1`.`t2` where ((`test1`.`t2`.`id` < 1000) and (`test1`.`t1`.`a` = `test1`.`t2`.`a`)) |
+---------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.01 sec)

文字セットの暗黙的な変換

パラメータのキャラクタ セットとフィールドのキャラクタ セットが異なる場合、直接比較することはできず、キャラクタ セットをconvert()変換するために変換フィールドに関数を追加する必要があり、インデックスが失敗する可能性があります。

テストテーブルの構造

  • データベースの文字セットは UTF8MB4 です
  • t1テーブルの文字セットは UTF8 です
  • t2テーブルの文字セットはUTF8MB4です
mysql> show create database test\G
*************************** 1. row ***************************
       Database: test
Create Database: CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET utf8mb4 */
mysql> show create table t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `id` int(11) NOT NULL,
  `a` varchar(20) DEFAULT NULL,
  `b` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> show create table t2\G
*************************** 1. row ***************************
       Table: t2
Create Table: CREATE TABLE `t2` (
  `id` int(11) NOT NULL,
  `a` varchar(20) DEFAULT NULL,
  `b` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.01 sec)

単一テーブルの例

-- 正常执行时,匹配字段的字符集(没有单独指定时继承表的字符集)
mysql> explain select * from t1 where a='1000';
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t1    | NULL       | ref  | a             | a    | 63      | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

-- 将参数转换不同的字符集,无法走到索引,而是全表扫描
mysql> explain select * from t1 where a=convert('1000' using utf8mb4);
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 2000 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)


-- show warnings可以看到优化器进行了转换,在t1.a上加了convert函数,从而无法走到索引
mysql> show warnings;
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                               |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `test`.`t1`.`id` AS `id`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (convert(`test`.`t1`.`a` using utf8mb4) = <cache>(convert('1000' using utf8mb4))) |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

さらに、次の点にも注意してください。

MySQL は内部的に、UTF8 から UTF8MB4 への変換など、低レベルのキャラクタ セットから高レベルのキャラクタ セットへの変換を優先します。

前の例では、convert()関数がt1.aに追加されましたが、次の例では、convert()関数がt2.aフィールドではなくパラメーターに追加されましたが、この状況によってパフォーマンスが低下することはありませんでした。

mysql> show create table t2\G
*************************** 1. row ***************************
       Table: t2
Create Table: CREATE TABLE `t2` (
  `id` int(11) NOT NULL,
  `a` varchar(20) DEFAULT NULL,
  `b` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
mysql> explain select * from t2 where a=convert('1000' using utf8);
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t2    | NULL       | ref  | a             | a    | 83      | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
mysql> show warnings;
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                   |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `test`.`t2`.`id` AS `id`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`a` = convert(convert('1000' using utf8) using utf8mb4)) |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

総括する:

  • テーブル フィールドの文字セットが下位レベルの文字セット (UTF8 など) で、受信値が上位レベルの文字セット (UTF8MB4 など) である場合、この時点でテーブル フィールドの文字セットが変換されます。これは、関数を使用するのと同じです。インデックスが無効です。
  • テーブル フィールドが上位レベルのキャラクタ セット (UTF8MB4 など) で、受信値が下位レベルのキャラクタ セット (UTF8 など) である場合、受信値はキャラクタ セットに変換され、インデックス エラーは発生しません。 。

ただし、通常、パラメータの文字セットを手動で変換する関数は使用しませんconvert()。次の 2 つのシナリオでは、無視されやすい暗黙的な型変換が発生する可能性があり、運用上の問題が発生します。

テーブル結合での文字セット変換

2 つのテーブルの接続フィールドの文字セットが一致しない場合、暗黙的な変換 ( convert()MySQL 内で追加された関数) が発生し、接続フィールドのインデックスに到達できず、最適なテーブル接続シーケンスが使用されない可能性があります。

インデックスが使用できないため、元々駆動テーブルだったテーブルが駆動テーブルとして使用される可能性があります。

例:

  • 通常の状況では、MySQL は小さな結果セットを持つテーブルを駆動テーブルとして優先します。この例では、それらはt2駆動​​テーブルとt1駆動テーブルです。
  • ただし、文字セットが異なるため、実際に実行される SQL は図のようになりますshow warnings文字セットを変換する関数をt1.aフィールドに追加すると、フィールドのインデックスに到達できなくなり、接続順序を変更する必要があります。 。convert()t1.a
mysql> explain select * from t1 left join t2 on t1.a=t2.a where t2.id<1000;
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra                 |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-----------------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 498649 |   100.00 | NULL                  |
|  1 | SIMPLE      | t2    | NULL       | ref  | PRIMARY,a     | a    | 83      | func |      1 |     4.79 | Using index condition |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-----------------------+
2 rows in set, 1 warning (0.00 sec)
mysql> show warnings;
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                                                                                                                |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `test`.`t1`.`id` AS `id`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`id` AS `id`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`id` < 1000) and (convert(`test`.`t1`.`a` using utf8mb4) = `test`.`t2`.`a`)) |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)




-- 在下面示例中,虽然也发生了类型转换,但是效率并没有变差,因为原本最优的连接顺序就是t1作为驱动表
mysql> explain select * from t1 left join t2 on t1.a=t2.a where t1.id<1000;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |  999 |   100.00 | Using where |
|  1 | SIMPLE      | t2    | NULL       | ref   | a             | a       | 83      | func |    1 |   100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)


mysql> show warnings;
+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                                                                                                                   |
+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `test`.`t1`.`id` AS `id`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`id` AS `id`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` left join `test`.`t2` on((convert(`test`.`t1`.`a` using utf8mb4) = `test`.`t2`.`a`)) where (`test`.`t1`.`id` < 1000) |
+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

ストアド プロシージャでの文字セット変換

これは比較的無視しやすいシナリオでもあり、運用環境での格納プロセス中に主キーが更新されたときに問題が発見されましたが、実行には 10 秒以上かかりました。

ストアドプロシージャ内の変数のキャラクタセットは()databaseのキャラクタセットから継承されます(作成時に指定することもできます)。テーブルフィールドのキャラクタセットがdatabase()のキャラクタセットと異なる場合、前と同様に暗黙的なキャラクタセット型変換が行われます。 1つが発生します。

例:

  • database文字セットはUTF8MB4です
  • character_set_clientおよびcollation_connectionストアド プロシージャを作成するときのcharacter_set_clientセッションのcollation_connection値です
  • ストアド プロシージャ内の変数の文字セットがデータベース レベルの文字セットと一致していることがテストされています。
-- 存储过程信息: Database Collation: utf8mb4_general_ci
mysql> show create procedure update_data\G
*************************** 1. row ***************************
           Procedure: update_data
            sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
    Create Procedure: CREATE DEFINER=`root`@`%` PROCEDURE `update_data`()
begin
  declare j int;
  declare n varchar(100);
   select charset(n);
  set j=1;
  while(j<=2000)do
set n = cast(j as char);
select 1,now();
    update t1 set b=concat(b,'1') where a=n;
select 2,now();
select sleep(1);
    set j=j+1;
  end while;
end
character_set_client: utf8mb4
collation_connection: utf8mb4_general_ci
  Database Collation: utf8mb4_general_ci
1 row in set (0.00 sec)
如下,在执行存储过程后,看到打印的变量n的字符集是utf8mb4


mysql> call update_data();
+------------+
| charset(n) |
+------------+
| utf8mb4    |
+------------+
1 row in set (0.00 sec)

インデックス フィールドに基づいて更新されるステートメントはa、実際にはフル テーブル スキャン (タイプ: インデックス、キー: プライマリ) を使用して次のようになります。

mysql> explain update t1 set b=concat(b,'1') where a=convert('1000' using utf8mb4);
+----+-------------+-------+------------+-------+---------------+---------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+--------+----------+-------------+
|  1 | UPDATE      | t1    | NULL       | index | NULL          | PRIMARY | 4       | NULL | 498649 |   100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+--------+----------+-------------+
1 row in set (0.00 sec)


-- 而正常情况下,执行计划为:
mysql> explain update t1 set b=concat(b,'1') where a='1000';
+----+-------------+-------+------------+-------+---------------+------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+------+---------+-------+------+----------+-------------+
|  1 | UPDATE      | t1    | NULL       | range | a             | a    | 63      | const |    1 |   100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+------+---------+-------+------+----------+-------------+
1 row in set (0.00 sec)

更新時間も0.00 秒から0.60 秒に変更されました。テーブル データの量が多い場合、フル テーブル スキャンは運用に大きな影響を与えます。

mysql> update t1 set b=concat(b,'1') where a='1000';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> update t1 set b=concat(b,'1') where a=convert('1000' using utf8mb4);
Query OK, 1 row affected (0.60 sec)
Rows matched: 1  Changed: 1  Warnings: 0

暗黙的な変換を回避する方法

データ型の暗黙的な変換の場合:

  1. 標準データ型の選択
  2. SQL パスに参加するフィールドのデータ型の一致

キャラクタ・セットの暗黙的な変換の場合: クライアント・キャラクタ・セット、サーバー側キャラクタ・セット、データベース・キャラクタ・セット、テーブル・キャラクタ・セット、およびフィールド・キャラクタ・セットの一貫性が維持されます。

さらに技術的な記事については、https: //opensource.actionsky.com/をご覧ください。

SQLEについて

SQLE は、開発環境から運用環境までの SQL 監査と管理をカバーする包括的な SQL 品質管理プラットフォームです。主流のオープンソース、商用および国内データベースをサポートし、開発、運用および保守のためのプロセス自動化機能を提供し、オンライン効率を向上させ、データ品質を向上させます。

SQL取得

タイプ 住所
リポジトリ https://github.com/actiontech/sqle
書類 https://actiontech.github.io/sqle-docs/
リリースニュース https://github.com/actiontech/sqle/releases
データ監査プラグイン開発ドキュメント https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse
「Qing Yu Nian 2」の海賊版リソースが npm にアップロードされたため、npmmirror は unpkg サービスを停止せざるを 得なくなりました。 周宏儀: すべての製品をオープンソースにすることを提案します 。ここで time.sleep(6) はどのような役割を果たしますか? ライナスは「ドッグフードを食べる」ことに最も積極的! 新しい iPad Pro は 12GB のメモリ チップを使用していますが、8GB のメモリを搭載していると主張しています。People 's Daily Online は、オフィス ソフトウェアのマトリョーシカ スタイルの充電についてレビューしています。「セット」を積極的に解決することによってのみ、 Flutter 3.22 と Dart 3.4 のリリース が可能になります。 Vue3 の新しい開発パラダイム、「ref/reactive」、「ref.value」不要 MySQL 8.4 LTS 中国語マニュアルリリース: データベース管理の新しい領域の習得に役立ちます Tongyi Qianwen GPT-4 レベルのメイン モデルの価格が値下げされました97%、1元と200万トークン
{{名前}}
{{名前}}

おすすめ

転載: my.oschina.net/actiontechoss/blog/11183928