資料庫如何做到多個任意欄位的檢索?(nosql方向)

現在使用的是mongodb,資料庫里很多欄位,但是我需要的查詢欄位數量和哪些欄位都不確定,給每個欄位建索引的話也只能支持單個欄位的檢索。複合索引,欄位一多組合就太多而且開銷肯定很大。

不知道這樣的查詢一般都是怎麼做的?


這其實是一個非常經典的難題

多個欄位,任意組合搜索,mongodb 我沒用過,但是我所知道的資料庫索引,遇到這類問題都是很頭大的。

以mysql為例,不管你設置了幾個索引,單鍵的還是複合的,執行查詢的時候,最多只能用到一個索引,記住這點,我姑且認為,mongodb也不例外。

那麼,你任意組合欄位搜索,是不是複合索引能滿足呢?不是

比如你做了ABC三個欄位複合索引(注意順序)

如果你查詢AB,這個索引是有效的,查詢A也沒問題,查詢AC,效率差一點,但是和查詢 A也差不太多,查詢BC,完蛋了,完全沒效率。這個索引毫無作用。

那麼,設置索引的原則是什麼呢?查詢索引掃描行數最少!

比如你查詢ABC,你設置了單鍵索引A,單鍵索引B,單鍵索引C,這裡哪個索引欄位的取值更分散,或者說哪個索引欄位的命中更少,用哪個索引效率就高,舉例說,你搜索了年齡和性別,用年齡做索引就比用性別做索引快。

mysql里,有時候資料庫不知道用什麼索引,需要force index一下(同一條SQL,不同版本會用到不同索引,效率差幾個數量級),mongodb我不清楚。

我建議你從數據出發,基於真實場景的日誌,把業務體系里常見的查詢濾出來,對最常見的查詢做針對性的索引優化,然後對非常不常見的查詢組合,從源頭是可以控制的。

如果能正確理解索引掃描行數,對這個問題的認識就會清晰。然後把不同的查詢拿出來分析,會用到哪個索引,索引掃描行數會在什麼量級,這個可以認為和查詢效率基本上是線性相關的。


現在使用的是mongodb,資料庫里很多欄位,但是我需要的查詢欄位數量和哪些欄位都不確定,給每個欄位建索引的話也只能支持單個欄位的檢索。複合索引,欄位一多組合就太多而且開銷肯定很大。

不知道這樣的查詢一般都是怎麼做的?

回答:

1.若量大的話,則建議走全文檢索服務;

2.若量不大的話,則可以走資料庫服務的模式,創建一張表存儲這些欄位值和對應值ID,這樣就可以減少搜索的值,然後創建一個所有欄位組合的索引,同時按最可能被使用和帥選率排列;


使用nark 資料庫,使用基於自動機的自壓縮索引:索引即數據,數據即索引,壓縮比媲美bzip2,同時又擁有資料庫的高速查詢能力


【欄位一多組合就太多而且開銷肯定很大】這句話不對。對於固定的欄位,組合起來的開銷比你用什麼亂七八糟的方法去模擬動態欄位的開銷小多了。


PostgreSQL 9.4 支持 JSONB 欄位,可以在 JSONB 上建 GIN 倒排索引。其它靠建模解決。


mysql全文檢索中文解決方案|MySQL 資料庫管理與開發 - 開發者論壇

&runSql("CREATE TABLE IF NOT EXISTS `ces_articles` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT "",
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`),
FULLTEXT KEY `url` (`url`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=DYNAMIC");
/*數據加入*/
$title="我愛大家啊,大家好";
$DBS-&>runSql("INSERT INTO `ces_articles` (id,title,url) VALUES (0,"". $title."","".str_replace("u","u",trim(json_encode($title)))."")");
$title="中國是什麼";
$DBS-&>runSql("INSERT INTO `ces_articles` (id,title,url) VALUES (0,"". $title."","".str_replace("u","u",trim(json_encode($title)))."")");
$title="http://ask.1912news.com";
$DBS-&>runSql("INSERT INTO `ces_articles` (id,title,url) VALUES (0,"". $title."","".str_replace("u","u",trim(json_encode($title)))."")");
$title="問答系統";
$DBS-&>runSql("INSERT INTO `ces_articles` (id,title,url) VALUES (0,"". $title."","".str_replace("u","u",trim(json_encode($title)))."")");
$title="1912網";
$DBS-&>runSql("INSERT INTO `ces_articles` (id,title,url) VALUES (0,"". $title."","".str_replace("u","u",trim(json_encode($title)))."")");
$title="零九網路";
$DBS-&>runSql("INSERT INTO `ces_articles` (id,title,url) VALUES (0,"". $title."","".str_replace("u","u",trim(json_encode($title)))."")");
//搜索:
$_GET["q"]="中國";
echo "q";
if(isset($_GET["q"])){$sql=" match(url) against ("".str_replace("u","u",trim(json_encode($_GET["q"])))."" IN BOOLEAN MODE)";}
$query = $DBS-&>getData("SELECT * FROM `ces_articles` where ".$sql." LIMIT 10");
echo "q";
if($query){
foreach ($query as $article){
echo $article["id"];
}
}

?&>


不要濫用mongo。

尋找其他方案,而不是趕鴨子上架。


mongodb已經支持全文搜索了 Text Indexes 。你的情況如果簡單的話應該就是在寫入的時候把所有欄位併到一塊兒,然後讓mongo自己來建full text index。

警告:mongo的全文檢索匹配的能力非常有限。取決於你的use case是什麼。如果你的要求比較複雜,比如要求處理同義詞單複數和時態的,可以看看elasticsearch或者直接用Lucene


不建議把全文檢索實現在 mongodb 中,因為沒有這個必要,mongo 的結構並不合適做全文檢索,並且會限制資料庫的可擴展性。

如果內容量大的話,用第三方的全文檢索引擎 elasticsearch.org?

如果內容量不是很大(比如,內容總量不超過伺服器內存的 1/2)那麼在 mongo 上套一個 redis 緩存,然後在 mongo 的 寫入 和 讀出時在 redis 緩存中建立檢索索引。 這樣做實現簡單,查詢速度飛快。Redis and a Full Text Indexing Solution ? myNoSQL


可以做一個專門的搜索引擎來管理索引,搜索引擎做查詢功能,,mysql提供數據存儲和數據源,資料庫只要一個主鍵索引即可


其實 lucene就是專門干這個的。

多個詞對應一個Value【document】,就是lucene的基本機構,這裡的多個詞可以成千上萬個。

全文索引一般的用法是:分詞程序把document的內容分成多個詞,然後這些詞對應到document上。

但依據樓主的要求,這裡不需要分詞程序。 直接在document下構造field: key1,key2......keyN,這個N是最大可能的欄位數。

把key1,key2......keyN和Value[document]【資料庫的行號/流水號】 一起按照lucene的規則添加索引,即可快速查詢。

lucene的結構很牛逼,對於數值類型,也可以使用大於,小於,between等邏輯判斷。樓主可以研究一下。


如果確實量比較大又比較複雜的話還是建議搭建檢索服務,也就是類似搜索引擎的方式。


這是多維度實時計算 參考此產品 Analytic Database Service 分析資料庫服務


加上Elasticsearch試試。


如果能夠考慮換存儲結構,elasticsearch似乎可以滿足,可以擁有任意欄位索引,當時有個項目有用到,那個項目數量級是千萬級別,欄位30多個,性能挺好的。當然這種方案很多代價,而且我也有很多的不確定性,僅供參考


但是我需要的查詢欄位數量和哪些欄位都不確定

你確定業務需求是這樣的嗎 ? 仔細分析過,是否能轉化到確定維度查詢 ? 否則,走全文檢索,沒有之一。

和什麼資料庫沒有關係,本質上「從一堆數據中找出符合條件的數據」,必須藉助已建立好的數據結構幫助你去快速篩選,如:在a欄位建立索引,然後查詢時 where a = xxx,可你『不確定』 .....


你主要應該根據實際使用情況來做索引,肯定不用全做,使用率低的操作慢那麼一點也沒什麼大事。


應該用全文索引吧,如sphinx


推薦閱讀:

哪裡有學習sql或者oracle資料庫的視頻教程?
為什麼沒有人實現 P2P 資料庫?
每天數據最少產生960W條記錄,我選Mysql還是Hbase?
學習做 DBA 的過程中需要精通哪些知識?
Mysql-InnoDB分表真的有意義嗎?

TAG:資料庫 | 數據 | 數據分析 | NoSQL | MongoDB |