SQLアンチパターン　プアマンズ・サーチエンジン

# プアマンズ・サーチエンジン

キーワード検索を高速で正確に行うことは簡単ではない。
SQLにおいて文字列の部分一致による比較は非効率性や不正確さにつながる。


# アンチパターン：パターンマッチ述語を使用する

SQLには文字列比較のためのパターンマッチがある。
キーワード検索等で一般的に使用されているLIKE演算子である。

LIKE演算子は0個以上の文字列と一致するワイルドカードを扱うことができる。
前後に％をつけることで文字列中に部分一致するワードとマッチすることができる。

パターンマッチはキーワード検索等で一般的だが問題点がある。

* パターンマッチはインデックスのメリットを受けることができない
* LIKE演算子を用いたパターンマッチでは意図しないマッチが生じる可能性がある

## インデックスのメリットを受けることができない

文字列に対するパターンマッチはテーブルスキャンが行われる。
それによってパターンマッチでのデータ取得はパフォーマンスの低下につながる。

## 意図しないマッチが生じる

以下のようなクエリを発行し「円」という文字をパターンマッチをした際に表の中の文字列が全てヒットする。

```SQL
SELECT * FROM Keyword WHERE keyword LIKE '%円%'
```

|keyword|
|:--|
|高<font color="Red">円</font>寺|
|日本<font color="Red">円</font>|
|<font color="Red">円</font>高|
|<font color="Red">円</font>安|
|三百<font color="Red">円</font>|
|<font color="Red">円</font>周率|
|<font color="Red">円円円円円</font>|

上記のようなパターンマッチは極端でこのような登録はしないとは思うが、このような関係のないワードどうしが同じテーブルに格納されている場合、意図しないワードまで取得される可能性がある。

# アンチパターンを用いても良い場合

・用途がシンプルな場合（検索したいケースが単純）
・パフォーマンスを考慮しなくても良いケース

# 解決策：適切なツールを使用する

* SQLの代わりに専用の全文検索エンジンを使用する
* SQL標準に準拠しつつも部分文字列マッチングより効果的な転置インデックスを使用する

# ベンダー拡張

主要なデータベース製品は、全文検索の要件に対する独自の解決策を用意している。
これらの独自機能は標準化されておらず、ベンダー間での互換性もない。

使用するデータベース製品が１つである場合にはSQLクエリと親和性が高く、高パフォーマンスなテキスト検索を行うための最善策とも言える。

# MySQLのフルインデックス

MySQLではMyISAMストレージエンジンのみがサポートするフルテキストインデックスが提供されている。
フルテキストインデックスを定義できるのはCHAR、VARCHAR、TEXT型の列。

※MySQL5.7までは日本語文書には使用できない

詳細については[MySQL 5.6 リファレンスマニュアル](https://dev.mysql.com/doc/refman/5.6/ja/innodb-fulltext-index.html)を参照してください。

# Oracleでのテキストインデックス

***CONTEXT***

* 単一のテキストの列に対してインデックスを作成
* インデックスを用いた検索にはCONTAINSを使用
* このインデックスはデータ変更に対する一貫性が維持されない
* PARAMETER(’’SYNC(ON COMMIT)') を追加すると自動で内容を同期

***CTXCAT***

* 短いテキストに特化したインデックス
* 同じテーブルの他の列と組み合わせて構造化
* インデックス化対象のデータがトランザクショによって更新されてもインデックスの一貫性は維持

***CTXXPATH***

* XMLドキュメントをexistsNode関数を用いて検索する用途に特化

***CTXRULE***

* CTXRULE型のインデックスは大量の文書解析ルールを設計し、分類結果を確認できる


詳細については[Oracle Text 概要](https://docs.oracle.com/cd/F19136_01/ccapp/creating-oracle-text-indexes.html#GUID-3505DB0D-B507-4D2E-A157-F16BD79FCF6E)を参照してください。

## Microsoft SQL Serverでの全文検索

* SQL Server2000以降では全文検索がサポートされている
* 言語、シソーラス、データ変更時の同期など複雑な構成オプションが使用可能

詳細については[SQL Server フルテキスト検索](https://docs.microsoft.com/ja-jp/sql/relational-databases/search/full-text-search?view=sql-server-ver15)を参照してください。

# PostgreSQLでのテキスト検索

* パフォーマンスを最適化するにはテキスト検索可能なTSVECTORを用いてコンテンツを格納
* PostgreSQLのテキスト検索演算子を用いてフルテキストインデックスを用い全文検索が可能

詳細については[テキスト検索に関する型](https://www.postgresql.jp/document/9.2/html/datatype-textsearch.html)を参照してください。

# SQLiteでの全文検索

* SQLiteの標準テーブルは効率的な全文検索をサポートしていない
* SQLiteの拡張機能のFTSを用いることで効率的な全文検索が利用できる

詳細については[SQLite FTS5 Extension](https://sqlite.org/fts5.html)を参照してください。

# サードパーティーのサーチエンジン

データベースに依存せずにテキストの全文検索をしたい場合はデータベースから独立して動作する検索エンジンが必要

# まとめ

問題を解決するために、必ずしもSQLを使う必要はありません

# 参考文献

[SQLアンチパターン](
https://www.amazon.co.jp/SQL%E3%82%A2%E3%83%B3%E3%83%81%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3-Bill-Karwin/dp/4873115892/ref=sr_1_1?adgrpid=104444684056&dchild=1&gclid=CjwKCAjw4_H6BRALEiwAvgfzqy-f83NTsyQkauo7gn6ysgAPmJvKyvuI5FaXFnxFmhVfCzCRRACsaBoCY-oQAvD_BwE&hvadid=447984765572&hvdev=c&hvlocphy=1009332&hvnetw=g&hvqmt=e&hvrand=13417269104929133208&hvtargid=kwd-335484809678&hydadcr=27264_11561110&jp-ad-ap=0&keywords=sql%E3%82%A2%E3%83%B3%E3%83%81%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3&qid=1599934568&sr=8-1&tag=googhydr-22)

![参考文献.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257405/b46d45ab-75ec-a620-eeb2-a422f6b1e659.jpeg)