序文
MYSQL
私は最近多くのデータベースを 使用しており、いくつかの非常に便利なガジェットを見つけました. 今日はそれらをあなたと共有します. それらがあなたの役に立てば幸いです.
1.group_concat
私たちの通常の作業では、group by
グループ化のシナリオがたくさんあります。
たとえば、ユーザー テーブル内の異なる名前を持つユーザーの特定の名前をカウントしたい場合はどうでしょうか。
具体的なSQLは次のとおりです。
SELECT name FROM `user` GROUP BY name;
しかし、同じ名前のコードをつなぎ合わせて別の列に配置したい場合はどうすればよいでしょうか?
答え:group_concat
関数を使用します。
例えば:
SELECT name,group_concat(code) FROM `user` GROUP BY name;
以下の結果:
関数を使用するとgroup_concat
、グループ化して文字列を形成した後、同じ名前のデータを簡単に結合して、逗号
.
2.char_length
长度
場合によっては文字を取得し、文字の長さに応じて処理を進める必要があります排序
。
MYSQL は、次のようないくつかの便利な関数を提供しますchar_length
。
文字長はこの関数で取得できます。
文字の長さと並べ替えを取得する SQL は次のとおりです。
SELECT user_id,user_name FROM `sys_user` WHERE user_name LIKE '%JM%'
ORDER BY CHAR_LENGTH(user_name) ASC LIMIT 5;
実行効果を図に示します。
名前フィールドでキーワードを使用した後模糊查询
、char_length
関数を使用して名前フィールドの文字長を取得し、長さを押します升序
。
3.見つける
: などの特定のキーワードを探している場合があり、JM
特定の文字列内でのその位置を知る必要があります。どうすればよいでしょうか?
答え:locate
関数を使用します。
locate関数を使用した後のSQL は次のようになります。
SELECT user_id,user_name FROM `sys_user` WHERE user_name LIKE '%JM%'
ORDER BY CHAR_LENGTH(user_name) ASC, LOCATE('JM',user_name) LIMIT 2,2;
以下の結果:
最初に長さで並べ替え、小さいものから順に並べます。長さが同じ場合は、キーワードに従って左から右にソートされ、左のものが最初にランク付けされます。
さらに、instr
次のposition
関数も使用できます。これらの関数はlocate
関数に似ているため、ここでは 1 つずつ紹介しません。
4.交換する
文字列のコンテンツの一部を置き換える必要があることがよくあります。たとえば、文字列内の文字 A を B に置き換えます。
この場合、関数を使用できますreplace
。
例えば:
UPDATE sys_user set user_name=REPLACE(user_name,'A','B') WHERE user_id=1;
これにより、文字置換機能を簡単に実装できます。
この関数で削除することもできます前后空格
:
UPDATE sys_user set user_name=REPLACE(user_name,' ','') WHERE user_name LIKE ' %';
UPDATE sys_user set user_name=REPLACE(user_name,' ','') WHERE user_name LIKE '% ';
この関数を使用してデータ コンテンツを置き換えるとjson格式
非常に便利です。
5.今
時間は良いことであり、データの範囲をすばやく狭めることができ、現在の時間を取得する必要があることがよくあります。
MYSQL で取得すると、次のような関数当前时间
を使用できます。now()
SELECT now() FROM sys_user LIMIT 1;
返される結果は次のとおりです。
が含まれます年月日时分秒
。
も返したい場合は毫秒
、次のように使用できますnow(3)
。
SELECT now(3) FROM sys_user LIMIT 1;
返される結果は次のとおりです。
とても使いやすく、覚えやすいです。
6.insert into ...を選択
仕事で必要になることが多いです插入数据
。
データを挿入するための従来の sql は次のようになります。
INSERT INTO `sys_user`(`user_id`, `dept_id`, `user_name`, `create_time`)
VALUES (6, '103', 'JM', now());
主に、決定された少量のデータを挿入するために使用されます。ただし、挿入する必要があるデータが大量にある場合、特に挿入するデータが別のテーブルまたは複数のテーブルの結果セットからのものである場合。
この場合、データを挿入する従来の方法を使用するのは少し無力です。
この時点で、MYSQL が提供する構文を使用できますinsert into ... select
。
例えば:
INSERT INTO `sys_user`(`user_id`, `dept_id`, `user_name`, `create_time`)
SELECT null,dept_id,user_name,now(3) FROM `sys_user_backup` WHERE dept_id in ('103','105');
このようにして、ユーザー バックアップ テーブルのデータの一部をユーザー テーブルに簡単に挿入できます。
7.insert into ... 無視
このようなシナリオに遭遇したかどうかはわかりません。1000 人のユーザーを挿入する前に、user_name に従ってユーザーが存在するかどうかを判断する必要があります。存在する場合、データは挿入されません。存在しない場合は、データを挿入する必要があります。
次のようにデータを直接挿入する場合:
INSERT INTO `sys_user`(`id`, `dept_id`, `user_name`, `create_time`)
VALUES (6, '103', 'JM', now());
sys_user テーブルの user_name フィールドが一意のインデックスを作成し、user_name が JM に等しいデータの一部がテーブルに既に存在するため、そうではありません。
実行直後にエラーが報告されました:
これには、挿入する前に判断を追加する必要があります。
もちろん、多くの人は、次のようなSQL ステートメントの後にステートメントを接合することで、not exists
重複データを防止するという目的を達成することもできます。
INSERT INTO `sys_user`(`user_id`, `dept_id`, `user_name`, `create_time`)
SELECT null,dept_id,user_name,now(3) FROM sys_user_backup
WHERE not exists (SELECT * FROM `sys_user` WHERE user_name = 'JM')
この sql は確かに要件を満たすことができますが、常に少し面倒に感じます。それで、もっと簡単な方法はありますか?
A:insert into ... ignore
文法は使えます。
例えば:
INSERT ignore INTO `sys_user`(`user_id`, `dept_id`, `user_name`, `create_time`)
VALUES (123, '105', 'JM', now(3));
この変換後、sys_user テーブルに user_name が JM であるデータが存在しない場合は、そのまま正常に挿入できます。
ただし、user_name が JM であるデータが sys_user テーブルに既に存在する場合、SQL ステートメントもエラーを報告せずに正常に実行できます。例外を無視するため、返される実行結果の影響を受ける行数は 0 であり、データを繰り返し挿入することはありません。
8.更新するために...を選択します
MYSQL データベースが付属しています悲观锁
. これは排他ロックです. ロックの粒度に応じて、表锁
,间隙锁
と行锁
.
実際のビジネス シナリオでは、同時実行性があまり高くない場合もありますが、データの正確性を確保するために、ペシミスティック ロックを使用することもできます。
例:ユーザーが減点し、ユーザーの操作が集中していない。ただし、ポイント自動付与システムの並行性も考慮する必要があるため、ポイント付与エラーが発生しないよう制限するペシミスティックロックを追加する必要があります。
この時点で、MYSQL の構文を使用できますselect ... for update
。
例えば:
BEGIN;
SELECT * FROM `sys_user` where user_id=1
FOR UPDATE;
//业务逻辑处理
UPDATE `sys_user` SET score = score -1 WHERE user_id=1;
COMMIT;
このように、レコードの行がトランザクションでロックされている場合for update
、トランザクションがコミットされるまで、他のトランザクションはその行のデータを更新できません。
update の前のid主键
条件は、テーブルのorでなければならないことに注意してください唯一索引
。そうしないと、行ロックが無効になり、無効になる可能性があります表锁
。
9.重複キー更新時
通常、データを挿入する前に、データが存在するかどうかを確認します。存在しない場合はデータを挿入します。既に存在する場合、データは挿入されませんが、結果は直接返されます。
並行性がほとんどないシナリオでは、このアプローチで問題はありません。ただし、データを挿入するリクエストに一定量の同時実行性がある場合、この方法では重複データが生成される可能性があります。
もちろん、次の加唯一索引
ような重複データを防ぐ方法はたくさんあります。加分布式锁
ただし、これらのソリューションはいずれも、2 番目の要求でデータを更新することはできず、通常、既に存在すると判断した直後に返されます。
この場合、on duplicate key update
構文を使用できます。
この構文は、データを挿入する前に判断し、主キーまたは一意のインデックスが存在しない場合は、データを挿入します。主キーまたは一意のインデックスが存在する場合、更新操作が実行されます。
更新が必要な特定のフィールドを指定できます。次に例を示します。
INSERT INTO `sys_user`(`user_id`, `dept_id`, `user_name`, `create_time`)
VALUES (null, '103', 'JM', now())
OM DUPLICATE KEY UPDATE user_name='JM',create_time=now();
このようなステートメントは、要件を簡単に満たすことができ、重複データを生成せず、最新のデータを更新することもできます。
ただし、同時実行性の高いシナリオで構文を使用すると問題が発生on duplicate key update
する可能性がある死锁
ため、実際の状況に応じて使用してください。
10.テーブルの作成を表示
場合によっては、テーブルのフィールドをすばやく表示したいことがあります。通常はdesc
、次のようなコマンドを使用します。
DESC `sys_dept`;
結果を図に示します。
フィールド名、フィールド タイプ、フィールド長、空にできるかどうか、主キーかどうか、sys_dept テーブルのデフォルト値などの情報を実際に確認できます。
テーブルのインデックス情報が見れないのですが、どのインデックスが作成されているのか知りたい場合はどうすればよいですか?
回答:show index
コマンドを使用します。
例えば:
SHOW INDEX FROM sys_dept;
テーブルのすべてのインデックスを見つけることもできます。
しかし、フィールドとインデックス データの表示を見ると、いつも少し奇妙に感じます. もっと直感的な方法はありますか?
回答:show create table
コマンドを使用する必要があります。
例えば:
show create table `order`;
実行結果を次の図に示します。
これは、データを展開する必要があることを意味します。非常に完全なテーブル作成ステートメント、テーブル名、フィールド名、フィールド タイプ、フィールド長、文字セット、主キー、インデックス、実行エンジンなどを見ることができますTable
。見られる。表名
Create Table
建表信息
非常に簡単です。
11.テーブル作成…選択
場合によっては、テーブルをすばやくバックアップする必要があります。
通常、次の 2 つの手順で実行できます。
-
一時テーブルを作成する
-
一時テーブルにデータを挿入する
一時テーブルを作成するには、次のコマンドを使用できます。
CREATE TABLE user_20221219 LIKE `sys_user`;
作成が成功すると、user_20221219 という名前が生成されます。テーブル構造は sys_user とまったく同じで新表
、 table のみです数据为空
。
次に次のコマンドを使用します。
INSERT INTO user_20221219 SELECT * FROM `sys_user`;
実行後、order テーブルのデータは user_20221219 テーブルに挿入され、データ バックアップの機能を実現します。
しかし、コマンドはありますか? 1 つのコマンドで上記の 2 つのステップの機能を実現できますか?
回答:create table ... select
コマンドを使用します。
例えば:
CREATE TABLE user_20221219
SELECT * FROM `sys_user`;
実行後、user_20221219 テーブルが作成され、新しく作成された user_20221219 に sys_user テーブルのデータが自動的に挿入されます。
1 つのコマンドで簡単に実行できます表备份
。
12.説明する
索引
多くの場合、 SQL ステートメントのパフォーマンスを最適化するために実行ステータスを確認する必要があります。
explain
A:コマンドを使用してmysql を表示すると执行计划
、 が表示されます索引的使用情况
。
例えば:
EXPLAIN SELECT * FROM `sys_user` WHERE dept_id=103;
結果:
これらの列は、インデックスの使用状況を判断するために使用できます。実行計画に含まれる列の意味を次の図に示します。
正直なところ、SQL ステートメントはインデックスを使用していません。インデックスが構築されていないことを除けば、最大の可能性はインデックスが無効であるということです。
インデックスの失敗の一般的な理由を次に示します。
上記の理由でない場合は、他の理由をさらに調査する必要があります。
13.プロセスリストを表示
オンラインの SQL またはデータベースに問題が発生することがあります。たとえば、データベース接続が多すぎる、または SQL ステートメントの実行時間が特に長いことが判明した場合などです。
この時、私たちは何をすべきでしょうか?
show processlist
回答:コマンドを使用して を表示できます当前线程执行情况
。
写真のように:
実行結果から、現在の接続ステータスを表示して、問題のあるクエリ ステートメントを特定できます。
-
IDスレッドID
-
SQL を実行するユーザー アカウント
-
ホスト SQL を実行するデータベースの IP とポート番号
-
db データベース名
-
Command デーモン、クエリ、スリープなどのコマンドを実行します。
-
時間 SQL の実行にかかった時間
-
状態 実行状態
-
info 実行情報。SQL 情報が含まれる場合があります。
異常な sql ステートメントが見つかった場合は、データベースに重大な問題が発生しないように直接強制終了できます。
14.mysqldump
MYSQL テーブルのデータをエクスポートする必要がある場合があります。
この場合mysqldump
、データをチェックアウトし、insert ステートメントに変換し、ファイルに書き込むツールを使用できます。これは、数据备份
.
ファイルを取得し、対応する挿入ステートメントを実行して、関連するテーブルを作成し、データを書き込みます。これは と同等です数据还原
。
mysqldump コマンドの構文は次のとおりです。mysqldump -h主机名 -P端口 -u用户名 -p密码 参数1,参数2.... > 文件名称.sql
リモート データベースのデータベースをバックアップします。
mysqldump -h 192.22.25.226 -u root -p123456 dbname > backup.sql